Work towards v1.0 data model with encapsulated weak_ptr as basis for instances

This commit is contained in:
Thomas Krijnen
2026-01-04 10:40:02 +01:00
parent f09ca658f1
commit 7098beb819
210 changed files with 28269 additions and 26471 deletions
+36 -38
View File
@@ -526,44 +526,42 @@ void GltfSerializer::setFile(IfcParse::IfcFile* f) {
return;
}
boost::optional<std::string> crs_epsg;
boost::optional<std::array<double, 3>> crs_x_axis;
boost::optional<std::array<double, 3>> eastings_northings_elevation;
std::optional<std::string> crs_epsg;
std::optional<std::array<double, 3>> crs_x_axis;
std::optional<std::array<double, 3>> eastings_northings_elevation;
aggregate_of_instance::ptr coordops;
std::vector<express::Base> coordops;
try {
coordops = f->instances_by_type("IfcCoordinateOperation");
} catch (IfcParse::IfcException&) {
// Ignored. Schema likely doesn't support IfcCoordinateOperation.
}
if (coordops) {
for (auto& coordop : *coordops) {
IfcUtil::IfcBaseClass* source_crs = coordop->as<IfcUtil::IfcBaseEntity>()->get("SourceCRS");
if (source_crs->declaration().is("IfcGeometricRepresentationContext")) {
IfcUtil::IfcBaseClass* target_crs = coordop->as<IfcUtil::IfcBaseEntity>()->get("TargetCRS");
auto name_attr = target_crs->as<IfcUtil::IfcBaseEntity>()->get("Name");
if (coordop->declaration().is("IfcMapConversion")) {
for (auto& coordop : coordops) {
express::Base source_crs = coordop.as<express::Entity>().get("SourceCRS");
if (source_crs.declaration().is("IfcGeometricRepresentationContext")) {
express::Base target_crs = coordop.as<express::Entity>().get("TargetCRS");
auto name_attr = target_crs.as<express::Entity>().get("Name");
if (coordop.declaration().is("IfcMapConversion")) {
if (!name_attr.isNull()) {
std::string epsg_code = name_attr;
crs_epsg = epsg_code;
if (!name_attr.isNull()) {
std::string epsg_code = name_attr;
crs_epsg = epsg_code;
// @todo in which unit are these?
double eastings = coordop->as<IfcUtil::IfcBaseEntity>()->get("Eastings");
double northings = coordop->as<IfcUtil::IfcBaseEntity>()->get("Northings");
double height = coordop->as<IfcUtil::IfcBaseEntity>()->get("OrthogonalHeight");
height = 0.;
// @todo in which unit are these?
double eastings = coordop.as<express::Entity>().get("Eastings");
double northings = coordop.as<express::Entity>().get("Northings");
double height = coordop.as<express::Entity>().get("OrthogonalHeight");
height = 0.;
eastings_northings_elevation = { { eastings, northings, height} };
eastings_northings_elevation = { { eastings, northings, height} };
auto xaxis_attr = coordop->as<IfcUtil::IfcBaseEntity>()->get("XAxisAbscissa");
auto yaxis_attr = coordop->as<IfcUtil::IfcBaseEntity>()->get("XAxisOrdinate");
if (!xaxis_attr.isNull() && !yaxis_attr.isNull()) {
double xaxis = xaxis_attr;
double yaxis = yaxis_attr;
auto xaxis_attr = coordop.as<express::Entity>().get("XAxisAbscissa");
auto yaxis_attr = coordop.as<express::Entity>().get("XAxisOrdinate");
if (!xaxis_attr.isNull() && !yaxis_attr.isNull()) {
double xaxis = xaxis_attr;
double yaxis = yaxis_attr;
crs_x_axis = { { xaxis, yaxis, 0. } };
}
crs_x_axis = { { xaxis, yaxis, 0. } };
}
}
}
@@ -573,9 +571,9 @@ void GltfSerializer::setFile(IfcParse::IfcFile* f) {
if (!crs_epsg) {
auto sites = f->instances_by_type("IfcSite");
if (sites && sites->size() == 1) {
auto lat_attr = (*sites->begin())->as<IfcUtil::IfcBaseEntity>()->get("RefLatitude");
auto lon_attr = (*sites->begin())->as<IfcUtil::IfcBaseEntity>()->get("RefLongitude");
if (sites.size() == 1) {
auto lat_attr = sites.front().as<express::Entity>().get("RefLatitude");
auto lon_attr = sites.front().as<express::Entity>().get("RefLongitude");
if (!lat_attr.isNull() && !lon_attr.isNull()) {
std::vector<int> lat_dms = lat_attr;
@@ -594,13 +592,13 @@ void GltfSerializer::setFile(IfcParse::IfcFile* f) {
double elev = 0.;
/*
auto elev_attr = (*sites->begin())->as<IfcUtil::IfcBaseEntity>()->get("RefElevation");
auto elev_attr = (*sites->begin()).as<express::Entity>().get("RefElevation");
if (!elev_attr->isNull()) {
elev = *elev_attr;
}
*/
crs_epsg.reset("EPSG:4326");
crs_epsg.emplace("EPSG:4326");
eastings_northings_elevation = { { lat, lon, elev } };
}
}
@@ -608,13 +606,13 @@ void GltfSerializer::setFile(IfcParse::IfcFile* f) {
auto contexts = f->instances_by_type_excl_subtypes("IfcGeometricRepresentationContext");
if (contexts && contexts->size() > 0) {
auto context = (*contexts->begin())->as<IfcUtil::IfcBaseEntity>();
auto north_attr = context->get("TrueNorth");
if (!contexts.empty()) {
auto context = contexts.front().as<express::Entity>();
auto north_attr = context.get("TrueNorth");
if (!north_attr.isNull()) {
IfcUtil::IfcBaseClass* north = north_attr;
if (north->declaration().is("IfcDirection")) {
std::vector<double> ratios = north->as<IfcUtil::IfcBaseEntity>()->get("DirectionRatios");
express::Base north = north_attr;
if (north.declaration().is("IfcDirection")) {
std::vector<double> ratios = north.as<express::Entity>().get("DirectionRatios");
crs_x_axis = { { ratios[1], -ratios[0], 0. } };
}
}
+2 -2
View File
@@ -36,9 +36,9 @@ private:
std::ofstream fstream_, tmp_fstream1_, tmp_fstream2_;
std::map<std::string, int> materials_, meshes_;
json json_, node_array_;
boost::optional<json> ecef_transform_, north_rotation_, z_up_transform_;
std::optional<json> ecef_transform_, north_rotation_, z_up_transform_;
int bufferViewId;
std::map<const IfcUtil::IfcBaseEntity*, size_t> node_indices_;
std::map<express::Base, size_t> node_indices_;
std::vector<size_t> roots_;
int writeMaterial(const ifcopenshell::geometry::taxonomy::style::ptr style);
+1 -1
View File
@@ -30,7 +30,7 @@ RocksDbSerializer::RocksDbSerializer(const std::string& input_filename, const st
}
namespace {
// @nb copied from IfcEntityInstanceData.cpp but operating on unresolved instances
// @nb copied from InstanceData.cpp but operating on unresolved instances
bool serialize(std::string& val, const IfcParse::reference_or_simple_type& t)
{
auto s = sizeof(size_t);
+281 -286
View File
@@ -97,7 +97,7 @@ bool SvgSerializer::ready() {
return true;
}
void SvgSerializer::write(path_object& p, const TopoDS_Shape& comp_or_wire, boost::optional<std::vector<double>> dash_array) {
void SvgSerializer::write(path_object& p, const TopoDS_Shape& comp_or_wire, std::optional<std::vector<double>> dash_array) {
/* ShapeFix_Wire fix;
Handle(ShapeExtend_WireData) data = new ShapeExtend_WireData;
for (TopExp_Explorer edges(result, TopAbs_EDGE); edges.More(); edges.Next()) {
@@ -361,7 +361,7 @@ void SvgSerializer::write(path_object& p, const TopoDS_Shape& comp_or_wire, boos
}
}
SvgSerializer::path_object& SvgSerializer::start_path(const gp_Pln& pln, const IfcUtil::IfcBaseEntity* storey, const std::string& id) {
SvgSerializer::path_object& SvgSerializer::start_path(const gp_Pln& pln, const express::Base& storey, const std::string& id) {
auto key = std::make_pair(std::make_pair(storey, ""), path_object());
SvgSerializer::path_object& p = paths.insert(key)->second;
drawing_metadata[key.first].pln_3d = pln;
@@ -370,7 +370,7 @@ SvgSerializer::path_object& SvgSerializer::start_path(const gp_Pln& pln, const I
}
SvgSerializer::path_object& SvgSerializer::start_path(const gp_Pln& pln, const std::string& drawing_name, const std::string& id) {
auto key = std::make_pair(std::make_pair(nullptr, drawing_name), path_object());
auto key = std::make_pair(std::make_pair(express::Base{}, drawing_name), path_object());
SvgSerializer::path_object& p = paths.insert(key)->second;
drawing_metadata[key.first].pln_3d = pln;
p.first = id;
@@ -378,11 +378,11 @@ SvgSerializer::path_object& SvgSerializer::start_path(const gp_Pln& pln, const s
}
namespace {
boost::optional<std::pair<const IfcUtil::IfcBaseEntity*, double>> storey_elevation_from_element(const IfcGeom::BRepElement* o) {
std::optional<std::pair<express::Base, double>> storey_elevation_from_element(const IfcGeom::BRepElement* o) {
for (const auto& p : o->parents()) {
if (p->type() == "IfcBuildingStorey") {
try {
double e = p->product()->get("Elevation");
double e = p->product().get("Elevation");
double storey_elevation = e * o->geometry().settings().get<ifcopenshell::geometry::settings::LengthUnit>().get();
return std::make_pair(p->product(), storey_elevation);
} catch (...) {
@@ -391,12 +391,12 @@ namespace {
break;
}
}
return boost::none;
return std::nullopt;
}
typedef std::pair<std::array<double, 3>, std::array<double, 3>> box_t;
boost::optional<TopoDS_Edge> edge_from_compound(TopoDS_Shape& compound) {
std::optional<TopoDS_Edge> edge_from_compound(TopoDS_Shape& compound) {
TopoDS_Iterator it(compound);
if (it.More()) {
TopoDS_Shape wire = it.Value();
@@ -412,7 +412,7 @@ namespace {
}
}
}
return boost::none;
return std::nullopt;
}
class almost {
@@ -433,7 +433,7 @@ namespace {
}
};
boost::optional<box_t> box_from_compound(TopoDS_Shape& compound) {
std::optional<box_t> box_from_compound(TopoDS_Shape& compound) {
/*
// in v0.8 apparently we don't get a solid/shell anymore because
// we no longer use PrimAPI, but rather resolve the box to an
@@ -446,17 +446,17 @@ namespace {
shell = TopoDS::Shell(exp.Current());
exp.Next();
if (exp.More()) {
return boost::none;
return std::nullopt;
}
}
else {
return boost::none;
return std::nullopt;
}
*/
auto& shell = compound;
if (IfcGeom::util::count(shell, TopAbs_FACE) != 6) {
return boost::none;
return std::nullopt;
}
TopExp_Explorer it(shell, TopAbs_FACE);
@@ -464,16 +464,16 @@ namespace {
const auto& face = TopoDS::Face(it.Current());
auto surf = BRep_Tool::Surface(face);
if (surf->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
return boost::none;
return std::nullopt;
}
auto pln = Handle(Geom_Plane)::DownCast(surf);
auto dz = std::abs(pln->Position().Direction().Z());
if (almost(0.) != dz && almost(1.) != dz) {
return boost::none;
return std::nullopt;
}
auto dy = std::abs(pln->Position().Direction().Y());
if (almost(0.) != dy && almost(1.) != dy) {
return boost::none;
return std::nullopt;
}
}
@@ -491,27 +491,27 @@ namespace {
};
template <typename It>
void enumerate_string_properties(const IfcUtil::IfcBaseEntity* product, It output_it) {
auto rels = product->get_inverse("IsDefinedBy");
for (auto& rel : *rels) {
if (rel->declaration().is("IfcRelDefinesByProperties")) {
auto pset = ((IfcUtil::IfcBaseClass*) ((IfcUtil::IfcBaseEntity*) rel)->get("RelatingPropertyDefinition"))->as<IfcUtil::IfcBaseEntity>();
if (!pset->declaration().is("IfcPropertySet")) {
void enumerate_string_properties(const express::Base& product, It output_it) {
auto rels = product.as<express::Entity>().get_inverse("IsDefinedBy");
for (auto& rel : rels) {
if (rel.declaration().is("IfcRelDefinesByProperties")) {
auto pset = ((express::Base)rel.get("RelatingPropertyDefinition")).as<express::Entity>();
if (!pset.declaration().is("IfcPropertySet")) {
continue;
}
std::string pset_name;
if (!pset->get("Name").isNull()) {
pset_name = (std::string) pset->get("Name");
if (!pset.get("Name").isNull()) {
pset_name = (std::string) pset.get("Name");
}
aggregate_of_instance::ptr props = pset->get("HasProperties");
for (auto& prop : *props) {
if (prop->declaration().is("IfcPropertySingleValue")) {
std::string name = ((IfcUtil::IfcBaseEntity*) prop)->get("Name");
if (((IfcUtil::IfcBaseEntity*) prop)->get("NominalValue").isNull()) {
std::vector<express::Base> props = pset.get("HasProperties");
for (auto& prop : props) {
if (prop.declaration().is("IfcPropertySingleValue")) {
std::string name = prop.as<express::Entity>().get("Name");
if (prop.as<express::Entity>().get("NominalValue").isNull()) {
continue;
}
IfcUtil::IfcBaseClass* v = ((IfcUtil::IfcBaseEntity*) prop)->get("NominalValue");
auto value = v->get_attribute_value(0);
express::Base v = prop.as<express::Entity>().get("NominalValue");
auto value = v.get_attribute_value(0);
if (value.type() == IfcUtil::Argument_STRING) {
std::string v_str = value;
*output_it++ = string_property{ pset_name, name, v_str };
@@ -524,25 +524,24 @@ namespace {
}
namespace {
boost::optional<std::string> get_curve_style_name(IfcUtil::IfcBaseEntity* item) {
auto refs = item->get_inverse("StyledByItem");
for (auto& ref : *refs) {
if (ref->declaration().is("IfcStyledItem")) {
aggregate_of_instance::ptr styles = ((IfcUtil::IfcBaseEntity*)ref)->get("Styles");
for (auto& s_ : *styles) {
auto s = (IfcUtil::IfcBaseEntity*) s_;
std::vector<IfcUtil::IfcBaseEntity*> pss;
if (s->declaration().is("IfcPresentationStyleAssignment")) {
aggregate_of_instance::ptr pstyles = s->get("Styles");
for (auto& ssss : *pstyles) {
pss.push_back((IfcUtil::IfcBaseEntity*) ssss);
std::optional<std::string> get_curve_style_name(const express::Base& item) {
auto refs = item.as<express::Entity>().get_inverse("StyledByItem");
for (auto& ref : refs) {
if (ref.declaration().is("IfcStyledItem")) {
std::vector<express::Base> styles = ref.as<express::Entity>().get("Styles");
for (auto& s : styles) {
std::vector<express::Entity> pss;
if (s.declaration().is("IfcPresentationStyleAssignment")) {
std::vector<express::Base> pstyles = s.as<express::Entity>().get("Styles");
for (auto& ssss : pstyles) {
pss.push_back(ssss.as<express::Entity>());
}
} else {
pss.push_back(s);
pss.push_back(s.as<express::Entity>());
}
for (auto& ps : pss) {
if (ps->declaration().is("IfcCurveStyle")) {
auto arg = ps->get("Name");
if (ps.declaration().is("IfcCurveStyle")) {
auto arg = ps.get("Name");
if (!arg.isNull()) {
return (std::string) arg;
}
@@ -551,18 +550,18 @@ namespace {
}
}
}
return boost::none;
return std::nullopt;
}
}
void SvgSerializer::write(const IfcGeom::BRepElement* brep_obj) {
boost::optional<std::string> object_type;
if (!brep_obj->product()->get("ObjectType").isNull()) {
object_type = static_cast<std::string>(brep_obj->product()->get("ObjectType"));
std::optional<std::string> object_type;
if (!brep_obj->product().get("ObjectType").isNull()) {
object_type = static_cast<std::string>(brep_obj->product().get("ObjectType"));
}
std::vector<boost::optional<std::vector<double>>> dash_arrays;
std::vector<std::optional<std::vector<double>>> dash_arrays;
auto itm = brep_obj->geometry().as_compound();
TopoDS_Shape compound_local = ((ifcopenshell::geometry::OpenCascadeShape*)itm)->shape();
@@ -571,9 +570,9 @@ void SvgSerializer::write(const IfcGeom::BRepElement* brep_obj) {
for (auto& x : brep_obj->geometry()) {
dash_arrays.emplace_back();
boost::optional<std::string> curve_style_name;
std::optional<std::string> curve_style_name;
if (file) {
auto item = (IfcUtil::IfcBaseEntity*) this->file->instance_by_id(x.ItemId());
auto item = this->file->instance_by_id(x.ItemId());
curve_style_name = get_curve_style_name(item);
}
@@ -621,11 +620,11 @@ void SvgSerializer::write(const IfcGeom::BRepElement* brep_obj) {
auto compound_unmirrored = make_transform_global.Shape();
if (is_section || is_elevation) {
boost::optional<double> scale;
boost::optional<std::pair<double, double>> size;
std::optional<double> scale;
std::optional<std::pair<double, double>> size;
auto e = edge_from_compound(compound_unmirrored);
boost::optional<gp_Pln> pln;
std::optional<gp_Pln> pln;
if (e) {
TopoDS_Edge global_edge = TopoDS::Edge(e->Moved(trsf));
double u0, u1;
@@ -638,7 +637,7 @@ void SvgSerializer::write(const IfcGeom::BRepElement* brep_obj) {
pln = gp_Pln(gp_Ax3(P, N, V));
}
}
else if (boost::optional<box_t> b = box_from_compound(compound_local)) {
else if (std::optional<box_t> b = box_from_compound(compound_local)) {
pln = gp_Pln().Transformed(trsf);
size = std::make_pair(
b->second[0] - b->first[0],
@@ -726,7 +725,7 @@ void SvgSerializer::write(const IfcGeom::BRepElement* brep_obj) {
}
auto p = storey_elevation_from_element(brep_obj);
const IfcUtil::IfcBaseEntity* storey = p ? p->first : nullptr;
auto storey = p ? p->first : express::Base{};
double elev = p ? p->second : std::numeric_limits<double>::quiet_NaN();
// @todo is it correct to call nameElement() here with a single storey (what if this element spans multiple?)
@@ -792,7 +791,7 @@ void SvgSerializer::write(const geometry_data& data) {
const std::vector<section_data>* section_heights_used = &section_heights_storage;
if (section_data_) {
section_heights_used = section_data_.get_ptr();
section_heights_used = section_data_ ? std::addressof(*section_data_) : nullptr;
} else {
if (data.storey) {
section_heights_storage.push_back(horizontal_plan{ data.storey, data.storey_elevation, +1. });
@@ -836,25 +835,25 @@ void SvgSerializer::write(const geometry_data& data) {
TopoDS_Wire annotation;
if (is_floor_plan_ && draw_door_arcs_ && data.product->declaration().is("IfcDoor")) {
if (is_floor_plan_ && draw_door_arcs_ && data.product.declaration().is("IfcDoor")) {
boost::optional<std::string> operation_type;
std::optional<std::string> operation_type;
try {
aggregate_of_instance::ptr rels;
if (data.product->declaration().schema()->name() == "IFC2X3") {
rels = data.product->get_inverse("IsDefinedBy");
std::vector<express::Entity> rels;
if (data.product.declaration().schema()->name() == "IFC2X3") {
rels = data.product.as<express::Entity>().get_inverse("IsDefinedBy");
} else {
// Damn you, IFC
rels = data.product->get_inverse("IsTypedBy");
rels = data.product.as<express::Entity>().get_inverse("IsTypedBy");
}
for (auto& rel : *rels) {
if (rel->declaration().name() == "IfcRelDefinesByType") {
IfcUtil::IfcBaseClass* ty = ((IfcUtil::IfcBaseEntity*)rel)->get("RelatingType");
const std::string& ty_entity_name = ty->declaration().name();
for (auto& rel : rels) {
if (rel.declaration().name() == "IfcRelDefinesByType") {
express::Base ty = rel.as<express::Entity>().get("RelatingType");
const std::string& ty_entity_name = ty.declaration().name();
// Damn you, IFC
if (ty_entity_name == "IfcDoorStyle" || ty_entity_name == "IfcDoorType") {
operation_type = (std::string)((IfcUtil::IfcBaseEntity*)ty)->get("OperationType");
operation_type = ty.as<express::Entity>().get("OperationType");
}
}
}
@@ -936,7 +935,7 @@ void SvgSerializer::write(const geometry_data& data) {
gp_Vec projection_direction;
gp_Pln projection_plane;
const IfcUtil::IfcBaseEntity* storey = nullptr;
express::Base storey;
std::string drawing_name;
bool use_hlr = always_project_;
@@ -996,7 +995,7 @@ void SvgSerializer::write(const geometry_data& data) {
}
// Exclude annotations, spaces and grids from HLR
if (any_in_front && !data.product->declaration().is("IfcAnnotation") && !data.product->declaration().is("IfcSpace") && !data.product->declaration().is("IfcGrid")) {
if (any_in_front && !data.product.declaration().is("IfcAnnotation") && !data.product.declaration().is("IfcSpace") && !data.product.declaration().is("IfcGrid")) {
TopoDS_Shape* compound_to_hlr = &compound_to_use;
TopoDS_Shape subtracted_shape;
@@ -1004,9 +1003,9 @@ void SvgSerializer::write(const geometry_data& data) {
bool should_subtract = false;
if (subtraction_settings_ == ON_SLABS_AT_FLOORPLANS) {
should_subtract = data.product->declaration().is("IfcSlab") && is_floor_plan_;
should_subtract = data.product.declaration().is("IfcSlab") && is_floor_plan_;
} else if (subtraction_settings_ == ON_SLABS_AND_WALLS) {
should_subtract = data.product->declaration().is("IfcSlab") || data.product->declaration().is("IfcWall");
should_subtract = data.product.declaration().is("IfcSlab") || data.product.declaration().is("IfcWall");
} else if (subtraction_settings_ == ALWAYS) {
should_subtract = true;
}
@@ -1118,7 +1117,7 @@ void SvgSerializer::write(const geometry_data& data) {
}
TopoDS_Compound profile_edges;
if (profile_threshold_ != -1 && !(data.product->declaration().is("IfcWall") || data.product->declaration().is("IfcSlab"))) {
if (profile_threshold_ != -1 && !(data.product.declaration().is("IfcWall") || data.product.declaration().is("IfcSlab"))) {
TopTools_IndexedDataMapOfShapeListOfShape map;
TopExp::MapShapesAndAncestors(*compound_to_hlr, TopAbs_EDGE, TopAbs_FACE, map);
if (map.Extent() > profile_threshold_) {
@@ -1277,7 +1276,7 @@ void SvgSerializer::write(const geometry_data& data) {
auto proj = projection_direction ^ bbdif ^ projection_direction;
std::string object_type;
auto ot_arg = data.product->get("ObjectType");
auto ot_arg = data.product.as<express::Entity>().get("ObjectType");
if (!ot_arg.isNull()) {
object_type = (std::string) ot_arg;
object_type.erase(std::remove_if(object_type.begin(), object_type.end(), [](char c) { return !std::isalnum(c); }), object_type.end());
@@ -1287,7 +1286,7 @@ void SvgSerializer::write(const geometry_data& data) {
auto xyz_global = gp_Pnt().Transformed(data.trsf);
int state = infront_or_behind(projection_plane, xyz_global);
if (data.product->declaration().is("IfcAnnotation") && // is an Annotation
if (data.product.declaration().is("IfcAnnotation") && // is an Annotation
(proj.Magnitude() > 1.e-5) && // when projected onto the view has a length
(is_floor_plan_
? (zmin >= range.first && zmin < (range.second - 1.e-5)) // the Z-coords are within the range of the building storey,
@@ -1457,7 +1456,7 @@ void SvgSerializer::write(const geometry_data& data) {
TopoDS_Wire wire = TopoDS::Wire(wires->Value(i));
if (wire.Closed() && (print_space_names_ || print_space_areas_) && data.product->declaration().is("IfcSpace")) {
if (wire.Closed() && (print_space_names_ || print_space_areas_) && data.product.declaration().is("IfcSpace")) {
// we explicitly specify the surface here, to later on
// simplify the projection from {x,y,z} to {u, v} because
// we know we can simply discard z.
@@ -1475,12 +1474,12 @@ void SvgSerializer::write(const geometry_data& data) {
}
if (file && data.product->declaration().is("IfcBuildingStorey") && storey_height_display_ != SH_NONE && wires->Length() == 1 && IfcGeom::util::count(wire, TopAbs_EDGE) == 1) {
if (file && data.product.declaration().is("IfcBuildingStorey") && storey_height_display_ != SH_NONE && wires->Length() == 1 && IfcGeom::util::count(wire, TopAbs_EDGE) == 1) {
std::string elev_str;
const double lu = file->getUnit("LENGTHUNIT").second;
auto a = data.product->get("Elevation");
auto a = data.product.as<express::Entity>().get("Elevation");
if (!a.isNull()) {
double elev = a;
@@ -1523,7 +1522,7 @@ void SvgSerializer::write(const geometry_data& data) {
auto d = (p1.XYZ() - p0.XYZ());
d.Normalize();
const double shll = storey_height_line_length_.get_value_or(2.);
const double shll = storey_height_line_length_.value_or(2.);
d *= shll;
gp_Pnt p1x(p0.XYZ() + d);
@@ -1579,7 +1578,7 @@ void SvgSerializer::write(const geometry_data& data) {
std::pair<const gp_Pnt*, const gp_Pnt*> furthest_points = { nullptr, nullptr };
double furthest_points_distance = 0.;
boost::optional<gp_Pnt> center_point;
std::optional<gp_Pnt> center_point;
BRepTopAdaptor_FClass2d fcls(largest_closed_wire_face, BRep_Tool::Tolerance(largest_closed_wire_face));
@@ -1625,8 +1624,8 @@ void SvgSerializer::write(const geometry_data& data) {
if (print_space_names_) {
labels.push_back(data.ifc_name);
}
if (print_space_names_ && data.product->declaration().is("IfcSpace")) {
auto attr = data.product->get("LongName");
if (print_space_names_ && data.product.declaration().is("IfcSpace")) {
auto attr = data.product.as<express::Entity>().get("LongName");
if (!attr.isNull()) {
std::string long_name = attr;
if (!long_name.empty()) {
@@ -1708,8 +1707,8 @@ std::array<std::array<double, 3>, 3> SvgSerializer::resize() {
cy = offset_2d_->second;
} else if (scale_) {
sc = (*scale_) * 1000;
cx = (xmax + xmin) / 2. * sc - size_->first * center_x_.get_value_or(0.5);
cy = (ymax + ymin) / 2. * sc - size_->second * center_y_.get_value_or(0.5);
cx = (xmax + xmin) / 2. * sc - size_->first * center_x_.value_or(0.5);
cy = (ymax + ymin) / 2. * sc - size_->second * center_y_.value_or(0.5);
} else {
if (calculated_scale_) {
sc = *calculated_scale_;
@@ -1772,7 +1771,7 @@ void SvgSerializer::draw_hlr(const gp_Pln& pln, const drawing_key& drawing_name)
// not on the TopoDS_Shape input.
TopoDS_Shape hlr_compound;
if (drawing_name.first == nullptr) {
if (!drawing_name.first) {
gp_Trsf trsf_mirror;
if (!mirror_y_) {
trsf_mirror.SetMirror(gp_Ax2(gp::Origin(), gp::DY()));
@@ -1830,7 +1829,7 @@ void SvgSerializer::resetScale() {
void SvgSerializer::addTextAnnotations(const drawing_key& k) {
auto& meta = drawing_metadata[k];
boost::optional<std::pair<double, double>> range;
std::optional<std::pair<double, double>> range;
if (k.first && section_data_) {
for (auto& sd : *section_data_) {
@@ -1843,130 +1842,128 @@ void SvgSerializer::addTextAnnotations(const drawing_key& k) {
}
}
aggregate_of_instance::ptr annotations;
std::vector<express::Base> annotations;
if (file) {
annotations = file->instances_by_type("IfcAnnotation");
}
if (annotations) {
for (auto& ann_ : *annotations) {
auto ann = (IfcUtil::IfcBaseEntity*) ann_;
for (auto& ann_ : annotations) {
auto ann = ann_.as<express::Entity>();
auto ot = ann->get("ObjectType");
auto nm = ann->get("Name");
auto ds = ann->get("Description");
auto pl = ann->get("ObjectPlacement");
auto ot = ann.get("ObjectType");
auto nm = ann.get("Name");
auto ds = ann.get("Description");
auto pl = ann.get("ObjectPlacement");
if (!ot.isNull() && !nm.isNull() && !ds.isNull() && !pl.isNull()) {
auto object_type = (std::string) ot;
auto name = (std::string) nm;
auto desc = (std::string) ds;
if (!ot.isNull() && !nm.isNull() && !ds.isNull() && !pl.isNull()) {
auto object_type = (std::string) ot;
auto name = (std::string) nm;
auto desc = (std::string) ds;
if (object_type == "Text") {
auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(file, geometry_settings_);
auto item = mapping->map(pl);
auto matrix = ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::matrix4>(item);
delete mapping;
if (item) {
gp_Trsf trsf;
auto& m = matrix->ccomponents();
trsf.SetValues(
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
m(1, 0), m(1, 1), m(1, 2), m(1, 3),
m(2, 0), m(2, 1), m(2, 2), m(2, 3)
);
if (object_type == "Text") {
auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(file, geometry_settings_);
auto item = mapping->map(pl);
auto matrix = ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::matrix4>(item);
delete mapping;
if (item) {
gp_Trsf trsf;
auto& m = matrix->ccomponents();
trsf.SetValues(
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
m(1, 0), m(1, 1), m(1, 2), m(1, 3),
m(2, 0), m(2, 1), m(2, 2), m(2, 3)
);
#ifdef TAXONOMY_USE_NAKED_PTR
delete matrix;
delete matrix;
#endif
auto v = gp_Pnt(trsf.TranslationPart());
auto v = gp_Pnt(trsf.TranslationPart());
auto z_local = gp::DZ().Transformed(trsf);
auto view_dir = z_local.Dot(meta.pln_3d.Axis().Direction());
auto z_local = gp::DZ().Transformed(trsf);
auto view_dir = z_local.Dot(meta.pln_3d.Axis().Direction());
if ((!range || (v.Z() >= range->first && v.Z() < range->second)) && view_dir > 0.99) {
if ((!range || (v.Z() >= range->first && v.Z() < range->second)) && view_dir > 0.99) {
gp_Trsf trsf_view;
trsf_view.SetTransformation(gp::XOY(), meta.pln_3d.Position());
v.Transform(trsf_view);
gp_Trsf trsf_view;
trsf_view.SetTransformation(gp::XOY(), meta.pln_3d.Position());
v.Transform(trsf_view);
auto svg_name = nameElement(ann);
auto svg_name = nameElement(ann);
if (object_type.size()) {
// postfix the object_type for CSS matching
boost::replace_all(svg_name, "class=\"IfcAnnotation\"", "class=\"IfcAnnotation " + object_type + "\"");
}
path_object* po;
if (k.first) {
po = &start_path(meta.pln_3d, k.first, svg_name);
} else {
po = &start_path(meta.pln_3d, k.second, svg_name);
}
boost::optional<double> font_size;
std::vector<std::string> tokens;
boost::split(tokens, name, boost::is_any_of("_"));
if (tokens.size() == 2) {
try {
font_size = boost::lexical_cast<double>(tokens.back());
}
catch (...) {}
}
// @todo column or row?
double z_rotation = gp::DX().Transformed(trsf).AngleWithRef(
meta.pln_3d.Position().XDirection(),
meta.pln_3d.Position().Direction()
);
z_rotation *= 180. / M_PI;
auto y = -v.Y();
util::string_buffer path;
// dominant-baseline="central" is not well supported in IE.
// so we add a 0.35 offset to the dy of the tspans
path.add(" <text text-anchor=\"left\" x=\"");
xcoords.push_back(path.add(v.X()));
path.add("\" y=\"");
ycoords.push_back(path.add(y));
path.add("\" transform=\"rotate(");
path.add(z_rotation);
path.add(" ");
xcoords.push_back(path.add(v.X()));
path.add(" ");
ycoords.push_back(path.add(y));
path.add(")\"");
if (font_size) {
path.add(" font-size=\"");
path.add(*font_size);
path.add("\"");
}
path.add(">");
std::vector<std::string> labels{ desc };
for (auto lit = labels.begin(); lit != labels.end(); ++lit) {
auto l = *lit;
IfcUtil::escape_xml(l);
double dy = labels.begin() == lit
? 0.0 // align bottom
: 1.0; // <- dy is relative to the previous text element, so
// always 1 for successive spans.
path.add("<tspan x=\"");
xcoords.push_back(path.add(v.X()));
path.add("\" dy=\"");
path.add(boost::lexical_cast<std::string>(dy));
path.add("em\">");
path.add(l);
path.add("</tspan>");
}
path.add("</text>");
po->second.push_back(path);
if (object_type.size()) {
// postfix the object_type for CSS matching
boost::replace_all(svg_name, "class=\"IfcAnnotation\"", "class=\"IfcAnnotation " + object_type + "\"");
}
path_object* po;
if (k.first) {
po = &start_path(meta.pln_3d, k.first, svg_name);
} else {
po = &start_path(meta.pln_3d, k.second, svg_name);
}
std::optional<double> font_size;
std::vector<std::string> tokens;
boost::split(tokens, name, boost::is_any_of("_"));
if (tokens.size() == 2) {
try {
font_size = boost::lexical_cast<double>(tokens.back());
}
catch (...) {}
}
// @todo column or row?
double z_rotation = gp::DX().Transformed(trsf).AngleWithRef(
meta.pln_3d.Position().XDirection(),
meta.pln_3d.Position().Direction()
);
z_rotation *= 180. / M_PI;
auto y = -v.Y();
util::string_buffer path;
// dominant-baseline="central" is not well supported in IE.
// so we add a 0.35 offset to the dy of the tspans
path.add(" <text text-anchor=\"left\" x=\"");
xcoords.push_back(path.add(v.X()));
path.add("\" y=\"");
ycoords.push_back(path.add(y));
path.add("\" transform=\"rotate(");
path.add(z_rotation);
path.add(" ");
xcoords.push_back(path.add(v.X()));
path.add(" ");
ycoords.push_back(path.add(y));
path.add(")\"");
if (font_size) {
path.add(" font-size=\"");
path.add(*font_size);
path.add("\"");
}
path.add(">");
std::vector<std::string> labels{ desc };
for (auto lit = labels.begin(); lit != labels.end(); ++lit) {
auto l = *lit;
IfcUtil::escape_xml(l);
double dy = labels.begin() == lit
? 0.0 // align bottom
: 1.0; // <- dy is relative to the previous text element, so
// always 1 for successive spans.
path.add("<tspan x=\"");
xcoords.push_back(path.add(v.X()));
path.add("\" dy=\"");
path.add(boost::lexical_cast<std::string>(dy));
path.add("em\">");
path.add(l);
path.add("</tspan>");
}
path.add("</text>");
po->second.push_back(path);
}
}
}
@@ -1992,7 +1989,7 @@ void SvgSerializer::finalize() {
drawing_metadata[p.first].matrix_3 = m;
}
if (!deferred_section_data_.is_initialized() && (auto_section_ || auto_elevation_)) {
if (!deferred_section_data_ && (auto_section_ || auto_elevation_)) {
deferred_section_data_.emplace();
}
@@ -2078,64 +2075,62 @@ void SvgSerializer::finalize() {
const auto& section = boost::get<vertical_section>(sd);
const auto& ax = section.plane.Position();
draw_hlr(ax, { nullptr, drawing_name });
draw_hlr(ax, { express::Base{}, drawing_name });
}
addTextAnnotations({ nullptr, drawing_name });
addTextAnnotations({express::Base{}, drawing_name});
if (file && storey_height_display_ != SH_NONE && pln && std::abs(pln->Position().Direction().Z()) < 1.e-5) {
auto storeys = file->instances_by_type("IfcBuildingStorey");
if (storeys) {
const double lu = file->getUnit("LENGTHUNIT").second;
for (auto& s : *storeys) {
auto storey = (IfcUtil::IfcBaseEntity*) s;
auto a = storey->get("Elevation");
if (!a.isNull()) {
double elev = a;
elev *= lu;
auto svg_name = nameElement(storey);
const double lu = file->getUnit("LENGTHUNIT").second;
for (auto& s : storeys) {
auto storey = s.as<express::Entity>();
auto a = storey.get("Elevation");
if (!a.isNull()) {
double elev = a;
elev *= lu;
auto svg_name = nameElement(storey);
gp_Pln elev_pln(gp_Ax3(gp_Pnt(0, 0, elev), gp::DZ(), gp::DX()));
//, pln->Position().XDirection()));
// auto ref_y = pln->Position().YDirection().XYZ().Dot(pln->Position().Location().XYZ());
gp_Pln elev_pln(gp_Ax3(gp_Pnt(0, 0, elev), gp::DZ(), gp::DX()));
//, pln->Position().XDirection()));
// auto ref_y = pln->Position().YDirection().XYZ().Dot(pln->Position().Location().XYZ());
double x0, y0, z0, x1, y1, z1;
bnd_.Get(x0, y0, z0, x1, y1, z1);
double x0, y0, z0, x1, y1, z1;
bnd_.Get(x0, y0, z0, x1, y1, z1);
// @todo this is a hack in order to get the auto elevations (which are 0.1 offset from
// the global bounding box) to include the storey height symbols.
x0 -= 0.2;
y0 -= 0.2;
z0 -= 0.2;
// @todo this is a hack in order to get the auto elevations (which are 0.1 offset from
// the global bounding box) to include the storey height symbols.
x0 -= 0.2;
y0 -= 0.2;
z0 -= 0.2;
x1 += 0.2;
y1 += 0.2;
z1 += 0.2;
x1 += 0.2;
y1 += 0.2;
z1 += 0.2;
const double shll = storey_height_line_length_.get_value_or(2.);
const double shll = storey_height_line_length_.value_or(2.);
BRepBuilderAPI_MakeFace mf(elev_pln, x0 - shll, x1 + shll, y0 - shll, y1 + shll);
gp_Trsf trsf;
TopoDS_Compound C;
BRep_Builder B;
B.MakeCompound(C);
B.Add(C, mf.Face());
std::string name;
auto a2 = storey->get("Name");
if (!a2.isNull()) {
name = (std::string) a2;
}
write(geometry_data{
C,{boost::none},trsf,storey,storey,elev,name,nameElement(storey)
});
BRepBuilderAPI_MakeFace mf(elev_pln, x0 - shll, x1 + shll, y0 - shll, y1 + shll);
gp_Trsf trsf;
TopoDS_Compound C;
BRep_Builder B;
B.MakeCompound(C);
B.Add(C, mf.Face());
std::string name;
auto a2 = storey.get("Name");
if (!a2.isNull()) {
name = (std::string) a2;
}
write(geometry_data{
C,{std::nullopt},trsf,storey,storey,elev,name,nameElement(storey)
});
}
}
}
auto m3 = resize();
auto k = std::make_pair(nullptr, drawing_name);
auto k = std::make_pair(express::Base{}, drawing_name);
drawing_metadata[k].matrix_3 = m3;
resetScale();
@@ -2146,7 +2141,7 @@ void SvgSerializer::finalize() {
std::multimap<drawing_key, path_object, storey_sorter>::const_iterator it;
boost::optional<drawing_key> previous;
std::optional<drawing_key> previous;
for (it = paths.begin(); it != paths.end(); ++it) {
if (!previous || it->first != *previous) {
if (previous) {
@@ -2269,7 +2264,7 @@ return oss.str();
}
}
std::string SvgSerializer::nameElement(const IfcUtil::IfcBaseEntity* storey, const IfcGeom::Element* elem) {
std::string SvgSerializer::nameElement(express::Base storey, const IfcGeom::Element* elem) {
auto n = elem->name();
IfcUtil::escape_xml(n);
@@ -2281,26 +2276,28 @@ std::string SvgSerializer::nameElement(const IfcUtil::IfcBaseEntity* storey, con
});
}
std::string SvgSerializer::idElement(const IfcUtil::IfcBaseEntity* elem) {
const std::string type = elem->declaration().is("IfcBuildingStorey") ? "storey" : "product";
std::string SvgSerializer::idElement(express::Base elem_) {
auto elem = elem_.as<express::Entity>();
const std::string type = elem.declaration().is("IfcBuildingStorey") ? "storey" : "product";
const std::string name =
(settings().get<ifcopenshell::geometry::settings::UseElementGuids>().get()
? static_cast<std::string>(elem->get("GlobalId"))
: ((settings().get<ifcopenshell::geometry::settings::UseElementNames>().get() && !elem->get("Name").isNull()))
? static_cast<std::string>(elem->get("Name"))
? static_cast<std::string>(elem.get("GlobalId"))
: ((settings().get<ifcopenshell::geometry::settings::UseElementNames>().get() && !elem.get("Name").isNull()))
? static_cast<std::string>(elem.get("Name"))
: (settings().get<ifcopenshell::geometry::settings::UseElementStepIds>().get())
? ("id-" + boost::lexical_cast<std::string>(elem->id()))
: IfcParse::IfcGlobalId(elem->get("GlobalId")).formatted());
? ("id-" + boost::lexical_cast<std::string>(elem.id()))
: IfcParse::IfcGlobalId(elem.get("GlobalId")).formatted());
return type + "-" + name;
}
std::string SvgSerializer::nameElement(const IfcUtil::IfcBaseEntity* elem) {
if (elem == 0) { return ""; }
std::string SvgSerializer::nameElement(express::Base elem_) {
auto elem = elem_.as<express::Entity>();
if (!elem) { return ""; }
const std::string& entity = elem->declaration().name();
const std::string& entity = elem.declaration().name();
std::string ifc_name;
if (!elem->get("Name").isNull()) {
ifc_name = (std::string) elem->get("Name");
if (!elem.get("Name").isNull()) {
ifc_name = (std::string) elem.get("Name");
IfcUtil::escape_xml(ifc_name);
}
@@ -2308,7 +2305,7 @@ std::string SvgSerializer::nameElement(const IfcUtil::IfcBaseEntity* elem) {
{"id", idElement(elem)},
{"class", entity},
{namespace_prefix_ + "name", ifc_name},
{namespace_prefix_ + "guid", elem->get("GlobalId")}
{namespace_prefix_ + "guid", elem.get("GlobalId")}
});
}
@@ -2316,30 +2313,28 @@ void SvgSerializer::setFile(IfcParse::IfcFile* f) {
file = f;
auto storeys = f->instances_by_type("IfcBuildingStorey");
if (!storeys || storeys->size() == 0) {
if (storeys.empty()) {
auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(file, geometry_settings_);
std::vector<const IfcParse::declaration*> to_derive_from;
to_derive_from.push_back(f->schema()->declaration_by_name("IfcBuilding"));
to_derive_from.push_back(f->schema()->declaration_by_name("IfcSite"));
for (auto it = to_derive_from.begin(); it != to_derive_from.end(); ++it) {
aggregate_of_instance::ptr insts = f->instances_by_type(*it);
if (insts) {
for (auto jt = insts->begin(); jt != insts->end(); ++jt) {
IfcUtil::IfcBaseEntity* product = (IfcUtil::IfcBaseEntity*) *jt;
if (!product->get("ObjectPlacement").isNull()) {
auto item = mapping->map(product->get("ObjectPlacement"));
auto matrix = ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::matrix4>(item);
gp_Trsf trsf;
if (matrix) {
// @todo shouldn't this take into account configurable section height?
setSectionHeight(matrix->translation_part()(2) + 1.);
auto insts = f->instances_by_type(*it);
for (auto& inst : insts) {
auto product = inst.as<express::Entity>();
if (!product.get("ObjectPlacement").isNull()) {
auto item = mapping->map(product.get("ObjectPlacement"));
auto matrix = ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::matrix4>(item);
gp_Trsf trsf;
if (matrix) {
// @todo shouldn't this take into account configurable section height?
setSectionHeight(matrix->translation_part()(2) + 1.);
#ifdef TAXONOMY_USE_NAKED_PTR
delete matrix;
delete matrix;
#endif
Logger::Warning("No building storeys encountered, used for reference:", product);
return;
}
Logger::Warning("No building storeys encountered, used for reference:", product);
return;
}
}
}
@@ -2351,7 +2346,7 @@ void SvgSerializer::setFile(IfcParse::IfcFile* f) {
}
}
void SvgSerializer::setSectionHeight(double h, const IfcUtil::IfcBaseEntity* storey) {
void SvgSerializer::setSectionHeight(double h, express::Base storey) {
section_data_.emplace();
section_data_->push_back(horizontal_plan{ storey, h, 0., std::numeric_limits<double>::infinity() });
}
@@ -2365,23 +2360,23 @@ void SvgSerializer::setSectionHeightsFromStoreys(double offset) {
section_data_.emplace();
auto storeys = file->instances_by_type("IfcBuildingStorey");
const double lu = file->getUnit("LENGTHUNIT").second;
if (storeys && storeys->size() > 0) {
for (auto& s : *storeys) {
auto attr_value = ((IfcUtil::IfcBaseEntity*)s)->get("Elevation");
if (!attr_value.isNull()) {
double elev;
try {
elev = attr_value;
} catch (std::exception& e) {
Logger::Error(e);
continue;
}
if (!section_data_->empty()) {
boost::get<horizontal_plan>(section_data_->back()).next_elevation = elev * lu;
}
section_data_->push_back(horizontal_plan{ (IfcUtil::IfcBaseEntity*)s, elev * lu, offset, std::numeric_limits<double>::infinity() });
}
}
if (!storeys.empty()) {
for (auto& s : storeys) {
auto attr_value = s.as<express::Entity>().get("Elevation");
if (!attr_value.isNull()) {
double elev;
try {
elev = attr_value;
} catch (std::exception& e) {
Logger::Error(e);
continue;
}
if (!section_data_->empty()) {
boost::get<horizontal_plan>(section_data_->back()).next_elevation = elev * lu;
}
section_data_->push_back(horizontal_plan{s, elev * lu, offset, std::numeric_limits<double>::infinity()});
}
}
} else {
section_data_->push_back(horizontal_plan_at_element{});
}
+53 -54
View File
@@ -57,56 +57,56 @@
#include <limits>
#include <array>
typedef std::pair<const IfcUtil::IfcBaseEntity*, std::string> drawing_key;
typedef std::pair<express::Base, std::string> drawing_key;
struct storey_sorter {
bool operator()(const drawing_key& ad, const drawing_key& bd) const {
if (ad.first == nullptr && bd.first != nullptr) {
if (!ad.first && bd.first) {
return false;
} else if (bd.first == nullptr && ad.first != nullptr) {
} else if (!bd.first && ad.first) {
return true;
} else if (ad.first == nullptr && bd.first == nullptr) {
} else if (!ad.first && !bd.first) {
return std::less<std::string>()(ad.second, bd.second);
}
auto a = ad.first;
auto b = bd.first;
const bool a_is_storey = a->declaration().is("IfcBuildingStorey");
const bool b_is_storey = b->declaration().is("IfcBuildingStorey");
const bool a_is_storey = a.declaration().is("IfcBuildingStorey");
const bool b_is_storey = b.declaration().is("IfcBuildingStorey");
if (a_is_storey && b_is_storey) {
boost::optional<double> a_elev, b_elev;
std::optional<double> a_elev, b_elev;
try {
a_elev = static_cast<double>(a->get("Elevation"));
b_elev = static_cast<double>(b->get("Elevation"));
a_elev = static_cast<double>(a.as<express::Entity>().get("Elevation"));
b_elev = static_cast<double>(b.as<express::Entity>().get("Elevation"));
} catch (...) {};
if (a_elev && b_elev) {
if (std::equal_to<double>()(*a_elev, *b_elev)) {
return std::less<unsigned int>()(a->id(), b->id());
return std::less<unsigned int>()(a.id(), b.id());
} else {
return std::less<double>()(*a_elev, *b_elev);
}
}
boost::optional<std::string> a_name, b_name;
std::optional<std::string> a_name, b_name;
try {
a_name = static_cast<std::string>(a->get("Name"));
b_name = static_cast<std::string>(b->get("Name"));
a_name = static_cast<std::string>(a.as<express::Entity>().get("Name"));
b_name = static_cast<std::string>(b.as<express::Entity>().get("Name"));
} catch (...) {};
if (a_name && b_name) {
if (std::equal_to<std::string>()(*a_name, *b_name)) {
return std::less<unsigned int>()(a->id(), b->id());
return std::less<unsigned int>()(a.id(), b.id());
} else {
return std::less<std::string>()(*a_name, *b_name);
}
}
}
return std::less<const IfcUtil::IfcBaseEntity*>()(a, b);
return std::less<express::Base>()(a, b);
}
};
struct horizontal_plan {
const IfcUtil::IfcBaseEntity* storey;
express::Base storey;
double elevation, offset, next_elevation;
};
@@ -116,18 +116,18 @@ struct vertical_section {
gp_Pln plane;
std::string name;
bool with_projection;
boost::optional<double> scale;
boost::optional<std::pair<double, double>> size;
std::optional<double> scale;
std::optional<std::pair<double, double>> size;
};
typedef boost::variant<horizontal_plan, horizontal_plan_at_element, vertical_section> section_data;
struct geometry_data {
TopoDS_Shape compound_local;
std::vector<boost::optional<std::vector<double>>> dash_arrays;
std::vector<std::optional<std::vector<double>>> dash_arrays;
gp_Trsf trsf;
const IfcUtil::IfcBaseEntity* product;
const IfcUtil::IfcBaseEntity* storey;
express::Base product;
express::Base storey;
double storey_elevation;
std::string ifc_name, svg_name;
};
@@ -211,15 +211,15 @@ namespace {
class hlr_calc {
private:
const HLRAlgo_Projector& projector_;
const std::list<std::pair<const IfcUtil::IfcBaseEntity*, TopoDS_Shape>>* product_shapes_ = nullptr;
const std::list<std::pair<express::Base, TopoDS_Shape>>* product_shapes_ = nullptr;
public:
typedef std::list<std::pair<const IfcUtil::IfcBaseEntity*, TopoDS_Shape>> result_type;
typedef std::list<std::pair<express::Base, TopoDS_Shape>> result_type;
hlr_calc(const HLRAlgo_Projector& projector) : projector_(projector)
{}
void set_product_shape(const std::list<std::pair<const IfcUtil::IfcBaseEntity*, TopoDS_Shape>>* product_shapes) {
void set_product_shape(const std::list<std::pair<express::Base, TopoDS_Shape>>* product_shapes) {
product_shapes_ = product_shapes;
}
@@ -233,13 +233,13 @@ namespace {
algo->Hide();
HLRBRep_HLRToShape hlr_shapes(algo);
if (product_shapes_) {
std::list<std::pair<const IfcUtil::IfcBaseEntity*, TopoDS_Shape>> r;
std::list<std::pair<express::Base, TopoDS_Shape>> r;
for (auto& p : *product_shapes_) {
r.push_back({ p.first, occt_join(hlr_shapes.OutLineVCompound(p.second), hlr_shapes.VCompound(p.second)) });
}
return r;
} else {
return { {nullptr, occt_join(hlr_shapes.OutLineVCompound(), hlr_shapes.VCompound())}};
return {{express::Base{}, occt_join(hlr_shapes.OutLineVCompound(), hlr_shapes.VCompound())}};
}
}
@@ -249,13 +249,13 @@ namespace {
HLRBRep_PolyHLRToShape hlr_shapes;
hlr_shapes.Update(algo);
if (product_shapes_) {
std::list<std::pair<const IfcUtil::IfcBaseEntity*, TopoDS_Shape>> r;
std::list<std::pair<express::Base, TopoDS_Shape>> r;
for (auto& p : *product_shapes_) {
r.push_back({ p.first, occt_join(hlr_shapes.OutLineVCompound(p.second), hlr_shapes.VCompound(p.second)) });
}
return r;
} else {
return { {nullptr, occt_join(hlr_shapes.OutLineVCompound(), hlr_shapes.VCompound()) } };
return {{express::Base{}, occt_join(hlr_shapes.OutLineVCompound(), hlr_shapes.VCompound())}};
}
}
};
@@ -366,7 +366,7 @@ namespace {
HLRAlgo_Projector projector_;
std::multimap<double, face_info> large_ortho_faces_;
std::list<std::pair<const IfcUtil::IfcBaseEntity*, TopoDS_Shape>> items_;
std::list<std::pair<express::Base, TopoDS_Shape>> items_;
public:
@@ -429,7 +429,7 @@ namespace {
return false;
}
void add(const TopoDS_Shape& s, const IfcUtil::IfcBaseEntity* product) {
void add(const TopoDS_Shape& s, express::Base product) {
if (!use_prefiltering_) {
items_.insert(items_.end(), {product, s});
return;
@@ -507,7 +507,7 @@ namespace {
}
}
std::list<std::pair<const IfcUtil::IfcBaseEntity*, TopoDS_Shape>> build() {
std::list<std::pair<express::Base, TopoDS_Shape>> build() {
size_t n_included = 0;
for (auto it = items_.begin(); it != items_.end(); ++it) {
if (!use_prefiltering_ || !is_obscured_(&it->second)) {
@@ -541,15 +541,15 @@ public:
protected:
stream_or_filename svg_file;
double xmin, ymin, xmax, ymax;
boost::optional<std::vector<section_data>> section_data_;
boost::optional<std::vector<section_data>> deferred_section_data_;
boost::optional<double> scale_, calculated_scale_, center_x_, center_y_;
boost::optional<double> storey_height_line_length_;
boost::optional<std::pair<double, double>> size_, offset_2d_;
boost::optional<std::string> space_name_transform_;
std::optional<std::vector<section_data>> section_data_;
std::optional<std::vector<section_data>> deferred_section_data_;
std::optional<double> scale_, calculated_scale_, center_x_, center_y_;
std::optional<double> storey_height_line_length_;
std::optional<std::pair<double, double>> size_, offset_2d_;
std::optional<std::string> space_name_transform_;
#if OCC_VERSION_HEX >= 0x70300
boost::optional<Bnd_OBB> view_box_3d_;
std::optional<Bnd_OBB> view_box_3d_;
#endif
@@ -568,15 +568,15 @@ protected:
int profile_threshold_;
IfcParse::IfcFile* file;
const IfcUtil::IfcBaseEntity* storey_;
express::Base storey_;
std::multimap<drawing_key, path_object, storey_sorter> paths;
std::map<drawing_key, drawing_meta> drawing_metadata;
std::map<const IfcUtil::IfcBaseEntity*, hlr_t> storey_hlr;
std::map<express::Base, hlr_t> storey_hlr;
float_item_list xcoords, ycoords, radii;
size_t xcoords_begin, ycoords_begin, radii_begin;
boost::optional<std::string> section_ref_, elevation_ref_, elevation_ref_guid_;
std::optional<std::string> section_ref_, elevation_ref_, elevation_ref_guid_;
std::list<geometry_data> element_buffer_;
@@ -621,7 +621,6 @@ public:
, unify_inputs_(false)
, profile_threshold_(-1)
, file(0)
, storey_(0)
, xcoords_begin(0)
, ycoords_begin(0)
, radii_begin(0)
@@ -638,16 +637,16 @@ public:
bool ready();
void write(const IfcGeom::TriangulationElement* /*o*/) {}
void write(const IfcGeom::BRepElement* o);
void write(path_object& p, const TopoDS_Shape& wire, boost::optional<std::vector<double>> dash_array=boost::none);
void write(path_object& p, const TopoDS_Shape& wire, std::optional<std::vector<double>> dash_array=std::nullopt);
void write(const geometry_data& data);
path_object& start_path(const gp_Pln& p, const IfcUtil::IfcBaseEntity* storey, const std::string& id);
path_object& start_path(const gp_Pln& p, const express::Base& storey, const std::string& id);
path_object& start_path(const gp_Pln& p, const std::string& drawing_name, const std::string& id);
bool isTesselated() const { return false; }
void finalize();
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
void setFile(IfcParse::IfcFile* f);
void setBoundingRectangle(double width, double height);
void setSectionHeight(double h, const IfcUtil::IfcBaseEntity* storey = 0);
void setSectionHeight(double h, express::Base storey = express::Base());
void setSectionHeightsFromStoreys(double offset=1.2);
void setPrintSpaceNames(bool b) { print_space_names_ = b; }
void setPrintSpaceAreas(bool b) { print_space_areas_ = b; }
@@ -660,17 +659,17 @@ public:
std::array<std::array<double, 3>, 3> resize();
void resetScale();
void setSectionRef(const boost::optional<std::string>& s) {
void setSectionRef(const std::optional<std::string>& s) {
section_ref_ = s;
}
void setElevationRef(const boost::optional<std::string>& s) {
void setElevationRef(const std::optional<std::string>& s) {
elevation_ref_ = s;
elevation_ref_guid_ = boost::none;
elevation_ref_guid_ = std::nullopt;
}
void setElevationRefGuid(const boost::optional<std::string>& s) {
elevation_ref_ = boost::none;
void setElevationRefGuid(const std::optional<std::string>& s) {
elevation_ref_ = std::nullopt;
elevation_ref_guid_ = s;
}
@@ -743,10 +742,10 @@ public:
void setDrawingCenter(double x, double y) {
center_x_ = x; center_y_ = y;
}
std::string nameElement(const IfcUtil::IfcBaseEntity* storey, const IfcGeom::Element* elem);
std::string nameElement(const IfcUtil::IfcBaseEntity* elem);
std::string idElement(const IfcUtil::IfcBaseEntity* elem);
std::string object_id(const IfcUtil::IfcBaseEntity* storey, const IfcGeom::Element* o) {
std::string nameElement(express::Base storey, const IfcGeom::Element* elem);
std::string nameElement(express::Base elem);
std::string idElement(express::Base elem);
std::string object_id(express::Base storey, const IfcGeom::Element* o) {
if (storey) {
return idElement(storey) + "-" + GeometrySerializer::object_id(o);
} else {
+1 -1
View File
@@ -284,7 +284,7 @@ void TtlWktSerializer::write(const IfcGeom::TriangulationElement* o)
Eigen::Map<const Eigen::Matrix<double, 3, Eigen::Dynamic>> vertex_map(o->geometry().verts().data(), 3, o->geometry().verts().size() / 3);
boost::optional<std::vector<std::vector<int>>::const_iterator> lowest_face;
std::optional<std::vector<std::vector<int>>::const_iterator> lowest_face;
double lowest_z = std::numeric_limits<double>::infinity();
for (const auto& f : o->geometry().polyhedral_faces_with_holes()) {
@@ -54,7 +54,7 @@ class format_value_visitor : public boost::static_visitor<std::string> {
public:
template <typename T>
json operator()(const T& t) const {
if constexpr (std::is_same_v<std::decay_t<T>, Derived> || std::is_same_v<std::decay_t<T>, boost::dynamic_bitset<>> || std::is_same_v<std::decay_t<T>, IfcUtil::IfcBaseClass*> || std::is_same_v<std::decay_t<T>, std::vector<int>> || std::is_same_v<std::decay_t<T>, std::vector<double>> || std::is_same_v<std::decay_t<T>, std::vector<std::string>> || std::is_same_v<std::decay_t<T>, std::vector<boost::dynamic_bitset<>>> || std::is_same_v<std::decay_t<T>, aggregate_of_instance::ptr> || std::is_same_v<std::decay_t<T>, aggregate_of_aggregate_of_instance::ptr> || std::is_same_v<std::decay_t<T>, std::vector<std::vector<int>>> || std::is_same_v<std::decay_t<T>, std::vector<std::vector<double>>> || std::is_same_v<std::decay_t<T>, empty_aggregate_t> || std::is_same_v<std::decay_t<T>, empty_aggregate_of_aggregate_t> || std::is_same_v<std::decay_t<T>, Blank>) {
if constexpr (std::is_same_v<std::decay_t<T>, Derived> || std::is_same_v<std::decay_t<T>, boost::dynamic_bitset<>> || std::is_same_v<std::decay_t<T>, express::Base> || std::is_same_v<std::decay_t<T>, std::vector<int>> || std::is_same_v<std::decay_t<T>, std::vector<double>> || std::is_same_v<std::decay_t<T>, std::vector<std::string>> || std::is_same_v<std::decay_t<T>, std::vector<boost::dynamic_bitset<>>> || std::is_same_v<std::decay_t<T>, std::vector<express::Base>> || std::is_same_v<std::decay_t<T>, std::vector<std::vector<express::Base>>> || std::is_same_v<std::decay_t<T>, std::vector<std::vector<int>>> || std::is_same_v<std::decay_t<T>, std::vector<std::vector<double>>> || std::is_same_v<std::decay_t<T>, empty_aggregate_t> || std::is_same_v<std::decay_t<T>, empty_aggregate_of_aggregate_t> || std::is_same_v<std::decay_t<T>, Blank>) {
return "";
} else if constexpr (std::is_same_v<std::decay_t<T>, boost::logic::tribool>) {
// @todo handle indeterminate
@@ -81,13 +81,27 @@ class get_type_visitor : public boost::static_visitor<std::string> {
// Returns related entity instances using IFC's objectified relationship
// model. The second and third argument require a member function pointer.
template <typename T, typename U, typename V, typename F, typename G>
auto get_related(T* t, F f, G g) {
typename U::list::ptr li = (*t.*f)()->template as<U>();
typename aggregate_of<V>::ptr acc(new aggregate_of<V>);
for (typename U::list::it it = li->begin(); it != li->end(); ++it) {
U* u = *it;
auto get_related(T t, F f, G g) {
auto li = (t.*f)();
std::vector<V> acc;
for (auto& u : li) {
try {
acc->push((*u.*g)()->template as<V>());
auto vs = (u.as<U>().*g)();
if constexpr (std::is_base_of_v<express::Base, decltype(vs)>) {
if (auto vv = vs.as<V>()) {
acc.push_back(vv);
}
} else if constexpr (std::is_base_of_v<express::Select, decltype(vs)>) {
if (auto vv = vs.concrete().as<V>()) {
acc.push_back(vv);
}
} else {
for (auto& v : vs) {
if (auto vv = v.as<V>()) {
acc.push_back(vv);
}
}
}
} catch (IfcParse::IfcException& e) {
Logger::Error(e);
}
@@ -95,7 +109,7 @@ auto get_related(T* t, F f, G g) {
return acc;
}
void format_entity_instance(IfcUtil::IfcBaseEntity* instance, json& tree, IfcUtil::IfcBaseEntity* parent = nullptr) {
void format_entity_instance(express::Base instance, json& tree, express::Base parent = express::Base()) {
/*
{
"id" : string, // Element GUID (IFC GloballyUniqueId)
@@ -119,7 +133,7 @@ void format_entity_instance(IfcUtil::IfcBaseEntity* instance, json& tree, IfcUti
auto write_to_json = [&](const std::string& keyJson, const std::string& keyIfc) {
AttributeValue val;
try {
val = instance->get(keyIfc);
val = instance.as<express::Entity>().get(keyIfc);
} catch (const IfcParse::IfcException&) {
// simply laziness like no attribute Tag on IfcProject
return;
@@ -132,29 +146,28 @@ void format_entity_instance(IfcUtil::IfcBaseEntity* instance, json& tree, IfcUti
write_to_json("id", "GlobalId");
write_to_json("name", "Name");
write_to_json("longName", "LongName");
child["type"] = instance->declaration().name();
child["type"] = instance.declaration().name();
if (parent) {
if (auto* rt = parent->as<IfcSchema::IfcRoot>()) {
child["parent"] = rt->GlobalId();
if (auto rt = parent.as<IfcSchema::IfcRoot>()) {
child["parent"] = rt.GlobalId();
}
}
// @todo groups
write_to_json("ObjectType", "ObjectType");
write_to_json("tag", "Tag");
if (auto* storey = instance->as<IfcSchema::IfcBuildingStorey>()) {
auto elevation = storey->Elevation();
if (auto storey = instance.as<IfcSchema::IfcBuildingStorey>()) {
auto elevation = storey.Elevation();
if (elevation) {
child["attributes"] = json::object({{"elevation", *elevation}});
}
}
if (auto* obj = instance->as<IfcSchema::IfcObject>()) {
IfcSchema::IfcPropertySetDefinition::list::ptr property_sets = get_related<IfcSchema::IfcObject, IfcSchema::IfcRelDefinesByProperties, IfcSchema::IfcPropertySetDefinition>(obj, &IfcSchema::IfcObject::IsDefinedBy, &IfcSchema::IfcRelDefinesByProperties::RelatingPropertyDefinition);
if (!property_sets && property_sets->size()) {
if (auto obj = instance.as<IfcSchema::IfcObject>()) {
auto property_sets = get_related<IfcSchema::IfcObject, IfcSchema::IfcRelDefinesByProperties, IfcSchema::IfcPropertySetDefinition>(obj, &IfcSchema::IfcObject::IsDefinedBy, &IfcSchema::IfcRelDefinesByProperties::RelatingPropertyDefinition);
if (!property_sets.empty()) {
child["propertySetIds"] = json::array();
for (IfcSchema::IfcPropertySetDefinition::list::it it = property_sets->begin(); it != property_sets->end(); ++it) {
IfcSchema::IfcPropertySetDefinition* pset = *it;
child["propertySetIds"].push_back(pset->GlobalId());
for (auto& pset : property_sets) {
child["propertySetIds"].push_back(pset.GlobalId());
}
}
}
@@ -166,9 +179,9 @@ void format_entity_instance(IfcUtil::IfcBaseEntity* instance, json& tree, IfcUti
// A function to be called recursively. Template specialization is used
// to descend into decomposition, containment and property relationships.
template <typename A>
void descend(A* instance, json& tree, IfcUtil::IfcBaseEntity* parent = nullptr) {
if (instance->declaration().is(IfcSchema::IfcObjectDefinition::Class())) {
descend(instance->template as<IfcSchema::IfcObjectDefinition>(), tree, parent);
void descend(A instance, json& tree, express::Base parent = express::Base()) {
if (instance.declaration().is(IfcSchema::IfcObjectDefinition::Class())) {
descend(instance.template as<IfcSchema::IfcObjectDefinition>(), tree, parent);
} else {
format_entity_instance(instance, tree);
}
@@ -179,10 +192,10 @@ void descend(A* instance, json& tree, IfcUtil::IfcBaseEntity* parent = nullptr)
// Descends into the tree by recursing into IfcRelContainedInSpatialStructure,
// IfcRelDecomposes, IfcRelDefinesByType, IfcRelDefinesByProperties relations.
template <>
void descend(IfcSchema::IfcObjectDefinition* product, json& tree, IfcUtil::IfcBaseEntity* parent) {
if (product->declaration().is(IfcSchema::IfcElement::Class())) {
auto voids = product->as<IfcSchema::IfcElement>()->FillsVoids();
if (voids && voids->size() == 1 && (*voids->begin())->RelatingOpeningElement() != parent) {
void descend(IfcSchema::IfcObjectDefinition product, json& tree, express::Base parent) {
if (product.declaration().is(IfcSchema::IfcElement::Class())) {
auto voids = product.as<IfcSchema::IfcElement>().FillsVoids();
if (voids.size() == 1 && voids.front().RelatingOpeningElement() != parent) {
// Fills are placed under their corresponding opening, return early to avoid duplication.
return;
}
@@ -190,46 +203,43 @@ void descend(IfcSchema::IfcObjectDefinition* product, json& tree, IfcUtil::IfcBa
format_entity_instance(product, tree, parent);
if (product->declaration().is(IfcSchema::IfcOpeningElement::Class())) {
IfcSchema::IfcOpeningElement* opening = product->as<IfcSchema::IfcOpeningElement>();
IfcSchema::IfcElement::list::ptr fills = get_related<IfcSchema::IfcOpeningElement, IfcSchema::IfcRelFillsElement, IfcSchema::IfcElement>(
if (auto opening = product.as<IfcSchema::IfcOpeningElement>()) {
auto fills = get_related<IfcSchema::IfcOpeningElement, IfcSchema::IfcRelFillsElement, IfcSchema::IfcElement>(
opening, &IfcSchema::IfcOpeningElement::HasFillings, &IfcSchema::IfcRelFillsElement::RelatedBuildingElement);
for (IfcSchema::IfcElement::list::it it = fills->begin(); it != fills->end(); ++it) {
descend(*it, tree, product);
for (auto& f : fills) {
descend(f, tree, product);
}
}
if (product->declaration().is(IfcSchema::IfcSpatialStructureElement::Class())) {
IfcSchema::IfcSpatialStructureElement* structure = product->as<IfcSchema::IfcSpatialStructureElement>();
if (auto structure = product.as<IfcSchema::IfcSpatialStructureElement>()) {
auto elements = get_related<IfcSchema::IfcSpatialStructureElement, IfcSchema::IfcRelContainedInSpatialStructure, IfcSchema::IfcObjectDefinition>(structure, &IfcSchema::IfcSpatialStructureElement::ContainsElements, &IfcSchema::IfcRelContainedInSpatialStructure::RelatedElements);
IfcSchema::IfcObjectDefinition::list::ptr elements = get_related<IfcSchema::IfcSpatialStructureElement, IfcSchema::IfcRelContainedInSpatialStructure, IfcSchema::IfcObjectDefinition>(structure, &IfcSchema::IfcSpatialStructureElement::ContainsElements, &IfcSchema::IfcRelContainedInSpatialStructure::RelatedElements);
for (IfcSchema::IfcObjectDefinition::list::it it = elements->begin(); it != elements->end(); ++it) {
descend(*it, tree, product);
for (auto& el : elements) {
descend(el, tree, product);
}
}
if (product->declaration().is(IfcSchema::IfcElement::Class())) {
IfcSchema::IfcElement* element = static_cast<IfcSchema::IfcElement*>(product);
IfcSchema::IfcOpeningElement::list::ptr openings = get_related<IfcSchema::IfcElement, IfcSchema::IfcRelVoidsElement, IfcSchema::IfcOpeningElement>(
if (auto element = product.as<IfcSchema::IfcElement>()) {
auto openings = get_related<IfcSchema::IfcElement, IfcSchema::IfcRelVoidsElement, IfcSchema::IfcOpeningElement>(
element, &IfcSchema::IfcElement::HasOpenings, &IfcSchema::IfcRelVoidsElement::RelatedOpeningElement);
for (IfcSchema::IfcOpeningElement::list::it it = openings->begin(); it != openings->end(); ++it) {
descend(*it, tree, product);
for (auto& op : openings) {
descend(op, tree, product);
}
}
#ifdef SCHEMA_IfcRelDecomposes_HAS_RelatedObjects
IfcSchema::IfcObjectDefinition::list::ptr structures = get_related<IfcSchema::IfcObjectDefinition, IfcSchema::IfcRelDecomposes, IfcSchema::IfcObjectDefinition>(product, &IfcSchema::IfcObjectDefinition::IsDecomposedBy, &IfcSchema::IfcRelDecomposes::RelatedObjects);
auto structures = get_related<IfcSchema::IfcObjectDefinition, IfcSchema::IfcRelDecomposes, IfcSchema::IfcObjectDefinition>(product, &IfcSchema::IfcObjectDefinition::IsDecomposedBy, &IfcSchema::IfcRelDecomposes::RelatedObjects);
#else
IfcSchema::IfcObjectDefinition::list::ptr structures = get_related<IfcSchema::IfcObjectDefinition, IfcSchema::IfcRelAggregates, IfcSchema::IfcObjectDefinition>(product, &IfcSchema::IfcObjectDefinition::IsDecomposedBy, &IfcSchema::IfcRelAggregates::RelatedObjects);
auto structures = get_related<IfcSchema::IfcObjectDefinition, IfcSchema::IfcRelAggregates, IfcSchema::IfcObjectDefinition>(product, &IfcSchema::IfcObjectDefinition::IsDecomposedBy, &IfcSchema::IfcRelAggregates::RelatedObjects);
structures->push(get_related<IfcSchema::IfcObjectDefinition, IfcSchema::IfcRelNests, IfcSchema::IfcObjectDefinition>(product, &IfcSchema::IfcObjectDefinition::IsNestedBy, &IfcSchema::IfcRelNests::RelatedObjects));
auto nested = get_related<IfcSchema::IfcObjectDefinition, IfcSchema::IfcRelNests, IfcSchema::IfcObjectDefinition>(product, &IfcSchema::IfcObjectDefinition::IsNestedBy, &IfcSchema::IfcRelNests::RelatedObjects);
structures.insert(structures.end(), nested.begin(), nested.end());
#endif
for (IfcSchema::IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
IfcSchema::IfcObjectDefinition* ob = *it;
for (auto& ob : structures) {
descend(ob, tree, product);
}
@@ -237,24 +247,24 @@ void descend(IfcSchema::IfcObjectDefinition* product, json& tree, IfcUtil::IfcBa
// all other relationships are not needed in JSON output
}
IfcSchema::IfcValue* get_value_from_prop(const IfcSchema::IfcProperty* prop) {
if (auto* psv = prop->as<IfcSchema::IfcPropertySingleValue>()) {
if (auto* nv = psv->NominalValue()) {
IfcSchema::IfcValue get_value_from_prop(IfcSchema::IfcProperty& prop) {
if (auto psv = prop.as<IfcSchema::IfcPropertySingleValue>()) {
if (auto nv = psv.NominalValue()) {
return nv;
}
}
// @todo other unit typs
return nullptr;
// @todo other unit types
return IfcSchema::IfcValue{};
}
IfcSchema::IfcUnit* get_unit_from_prop(const IfcSchema::IfcProperty* prop) {
if (auto* psv = prop->as<IfcSchema::IfcPropertySingleValue>()) {
if (auto* un = psv->Unit()) {
IfcSchema::IfcUnit get_unit_from_prop(IfcSchema::IfcProperty& prop) {
if (auto psv = prop.as<IfcSchema::IfcPropertySingleValue>()) {
if (auto un = psv.Unit()) {
return un;
}
}
// @todo other unit typs
return nullptr;
// @todo other unit types
return IfcSchema::IfcUnit{};
}
} // namespace
@@ -262,12 +272,12 @@ IfcSchema::IfcUnit* get_unit_from_prop(const IfcSchema::IfcProperty* prop) {
void POSTFIX_SCHEMA(JsonSerializer)::finalize() {
json output;
IfcSchema::IfcProject::list::ptr projects = file->instances_by_type<IfcSchema::IfcProject>();
if (projects->size() != 1) {
auto projects = file->instances_by_type<IfcSchema::IfcProject>();
if (projects.size() != 1) {
Logger::Message(Logger::LOG_ERROR, "Expected a single IfcProject");
return;
}
IfcSchema::IfcProject* project = *projects->begin();
IfcSchema::IfcProject project = projects.front();
auto catch_exceptions = [this](const auto& fn) {
try {
@@ -279,12 +289,12 @@ void POSTFIX_SCHEMA(JsonSerializer)::finalize() {
}
};
output["id"] = catch_exceptions([&]() { return file->header().file_name()->name(); });
output["projectId"] = catch_exceptions([&]() { return project->GlobalId(); });
output["author"] = catch_exceptions([&]() { return file->header().file_name()->author().empty() ? "unknown" : file->header().file_name()->author().front(); });
output["createdAt"] = catch_exceptions([&]() { return file->header().file_name()->time_stamp(); });
output["schema"] = catch_exceptions([&]() { return file->header().file_schema()->schema_identifiers().front(); }); // without schema we would not be here
output["creatingApplication"] = catch_exceptions([&]() { return file->header().file_name()->originating_system(); });
output["id"] = catch_exceptions([&]() { return file->header().file_name().name(); });
output["projectId"] = catch_exceptions([&]() { return project.GlobalId(); });
output["author"] = catch_exceptions([&]() { return file->header().file_name().author().empty() ? "unknown" : file->header().file_name().author().front(); });
output["createdAt"] = catch_exceptions([&]() { return file->header().file_name().time_stamp(); });
output["schema"] = catch_exceptions([&]() { return file->header().file_schema().schema_identifiers().front(); }); // without schema we would not be here
output["creatingApplication"] = catch_exceptions([&]() { return file->header().file_name().originating_system(); });
output["properties"] = json::array();
output["propertySets"] = json::array();
output["units"] = json::array();
@@ -293,18 +303,33 @@ void POSTFIX_SCHEMA(JsonSerializer)::finalize() {
output["groups"] = json::array();
// Maps for deduplication of properties and quantities
std::map<const IfcUtil::IfcBaseEntity*, size_t> property_to_index;
std::map<express::Entity, size_t> property_to_index;
std::unordered_map<json, std::size_t> json_to_index;
// Obtain sequence of units because properties, quantities reference them by index.
// IfcUnit is a select of IfcDerivedUnit, IfcMonetaryUnit and IfcNamedUnit.
// Unfortunately, instances_by_type() does not support select types directly (even though there isn't a real reason for that).
IfcSchema::IfcUnit::list::ptr units(new IfcSchema::IfcUnit::list);
units->push(file->instances_by_type<IfcSchema::IfcDerivedUnit>()->as<IfcSchema::IfcUnit>());
units->push(file->instances_by_type<IfcSchema::IfcMonetaryUnit>()->as<IfcSchema::IfcUnit>());
units->push(file->instances_by_type<IfcSchema::IfcNamedUnit>()->as<IfcSchema::IfcUnit>());
std::vector<IfcSchema::IfcUnit> units;
{
auto vs = file->instances_by_type<IfcSchema::IfcDerivedUnit>();
for (auto& v : vs) {
units.push_back(v);
}
}
{
auto vs = file->instances_by_type<IfcSchema::IfcMonetaryUnit>();
for (auto& v : vs) {
units.push_back(v);
}
}
{
auto vs = file->instances_by_type<IfcSchema::IfcNamedUnit>();
for (auto& v : vs) {
units.push_back(v);
}
}
auto format_property = [&](const IfcUtil::IfcBaseEntity* prop_) {
auto format_property = [&](const express::Entity& prop_) {
json jprop;
/*
{
@@ -315,23 +340,23 @@ void POSTFIX_SCHEMA(JsonSerializer)::finalize() {
"valueType": "boolean"
},
*/
if (auto* prop = prop_->as<IfcSchema::IfcProperty>()) {
jprop["name"] = prop->Name();
jprop["ifcPropertyType"] = prop->declaration().name();
if (auto* val = get_value_from_prop(prop)) {
jprop["ifcValueType"] = val->declaration().name();
jprop["value"] = val->data().get_attribute_value(nullptr, nullptr, 0, 0).apply_visitor(format_value_visitor{});
jprop["valueType"] = val->data().get_attribute_value(nullptr, nullptr, 0, 0).apply_visitor(get_type_visitor{});
if (auto prop = prop_.as<IfcSchema::IfcProperty>()) {
jprop["name"] = prop.Name();
jprop["ifcPropertyType"] = prop.declaration().name();
if (auto val = get_value_from_prop(prop)) {
jprop["ifcValueType"] = val.concrete().declaration().name();
jprop["value"] = val.concrete().data()->get_attribute_value(0).apply_visitor(format_value_visitor{});
jprop["valueType"] = val.concrete().data()->get_attribute_value(0).apply_visitor(get_type_visitor{});
}
if (auto* unit = get_unit_from_prop(prop)) {
jprop["unit"] = std::distance(units->begin(), std::find(units->begin(), units->end(), unit));
if (auto unit = get_unit_from_prop(prop)) {
jprop["unit"] = std::distance(units.begin(), std::find(units.begin(), units.end(), unit));
}
}
return jprop;
};
auto format_quantity = [&](const IfcUtil::IfcBaseEntity* qto_) {
auto format_quantity = [&](const express::Entity& qto_) {
json jprop;
/*
{
@@ -342,15 +367,15 @@ void POSTFIX_SCHEMA(JsonSerializer)::finalize() {
"unit": 3
}
*/
if (auto* qto = qto_->as<IfcSchema::IfcPhysicalQuantity>()) {
jprop["name"] = qto->Name();
jprop["ifcPropertyType"] = qto->declaration().name();
if (auto* prop = qto->as<IfcSchema::IfcPhysicalSimpleQuantity>()) {
jprop["ifcValueType"] = prop->declaration().attributes()[0]->name();
jprop["value"] = prop->data().get_attribute_value(nullptr, nullptr, 0, 3).apply_visitor(format_value_visitor{});
if (auto qto = qto_.as<IfcSchema::IfcPhysicalQuantity>()) {
jprop["name"] = qto.Name();
jprop["ifcPropertyType"] = qto.declaration().name();
if (auto prop = qto.as<IfcSchema::IfcPhysicalSimpleQuantity>()) {
jprop["ifcValueType"] = prop.declaration().as_entity()->attributes()[0]->name();
jprop["value"] = prop.data()->get_attribute_value(3).apply_visitor(format_value_visitor{});
jprop["valueType"] = "number";
if (auto* unit = prop->Unit()) {
jprop["unit"] = std::distance(units->begin(), std::find(units->begin(), units->end(), unit));
if (auto unit = prop.Unit()) {
jprop["unit"] = std::distance(units.begin(), std::find(units.begin(), units.end(), unit));
}
}
}
@@ -358,7 +383,7 @@ void POSTFIX_SCHEMA(JsonSerializer)::finalize() {
};
auto deduplicate = [&](auto base_formatter) {
return [&, base_formatter](const IfcUtil::IfcBaseEntity* prop) mutable -> std::size_t {
return [&, base_formatter](const express::Entity& prop) mutable -> std::size_t {
if (auto it = property_to_index.find(prop); it != property_to_index.end()) {
return it->second;
}
@@ -382,23 +407,23 @@ void POSTFIX_SCHEMA(JsonSerializer)::finalize() {
auto quantity_index_for = deduplicate(format_quantity);
auto pset_predef_or_qsets = file->instances_by_type<IfcSchema::IfcPropertySetDefinition>();
for (auto& inst : *pset_predef_or_qsets) {
for (auto& inst : pset_predef_or_qsets) {
std::vector<size_t> property_indices;
if (auto* pset = inst->as<IfcSchema::IfcPropertySet>()) {
auto props = pset->HasProperties();
for (auto& prop : *props) {
if (auto pset = inst.as<IfcSchema::IfcPropertySet>()) {
auto props = pset.HasProperties();
for (auto& prop : props) {
std::size_t index = property_index_for(prop);
property_indices.push_back(index);
}
} else if (auto* qset = inst->as<IfcSchema::IfcElementQuantity>()) {
auto qtos = qset->Quantities();
for (auto& qto : *qtos) {
} else if (auto qset = inst.as<IfcSchema::IfcElementQuantity>()) {
auto qtos = qset.Quantities();
for (auto& qto : qtos) {
std::size_t index = quantity_index_for(qto);
property_indices.push_back(index);
}
#ifdef SCHEMA_HAS_IfcPreDefinedPropertySet
// ifc2x3 does not have this type yet, just inherits from IfcPropertySetDefinition
} else if (auto* pset = inst->as<IfcSchema::IfcPreDefinedPropertySet>()) {
} else if (auto pset = inst.as<IfcSchema::IfcPreDefinedPropertySet>()) {
#else
} else {
#endif
@@ -424,13 +449,13 @@ void POSTFIX_SCHEMA(JsonSerializer)::finalize() {
"properties" : [ 0, 1, 2 ]
},
*/
output["propertySets"].push_back(json::object({{"id", inst->GlobalId()},
{"name", *inst->Name()}, // @todo optional
{"type", inst->declaration().name()},
output["propertySets"].push_back(json::object({{"id", inst.GlobalId()},
{"name", *inst.Name()}, // @todo optional
{"type", inst.declaration().name()},
{"properties", property_indices}}));
}
for (auto& unit : *units) {
for (auto& unit : units) {
/*
{
"name": string, // Unit symbol/name
@@ -465,67 +490,67 @@ void POSTFIX_SCHEMA(JsonSerializer)::finalize() {
}
*/
json junit;
junit["className"] = unit->declaration().name();
if (auto* siunit = unit->as<IfcSchema::IfcSIUnit>()) {
junit["className"] = unit.concrete().declaration().name();
if (auto siunit = unit.concrete().as<IfcSchema::IfcSIUnit>()) {
// @todo figure out how to encode name for si units
std::string unit_name = "";
junit["unitEnum"] = IfcSchema::IfcUnitEnum::ToString(siunit->UnitType());
if (siunit->Prefix()) {
junit["prefix"] = IfcSchema::IfcSIPrefix::ToString(*siunit->Prefix());
unit_name.push_back(IfcSchema::IfcSIPrefix::ToString(*siunit->Prefix())[0]);
junit["unitEnum"] = IfcSchema::IfcUnitEnum::ToString(siunit.UnitType());
if (siunit.Prefix()) {
junit["prefix"] = IfcSchema::IfcSIPrefix::ToString(*siunit.Prefix());
unit_name.push_back(IfcSchema::IfcSIPrefix::ToString(*siunit.Prefix())[0]);
}
unit_name.push_back(IfcSchema::IfcSIUnitName::ToString(siunit->Name())[0]);
unit_name.push_back(IfcSchema::IfcSIUnitName::ToString(siunit.Name())[0]);
boost::to_lower(unit_name);
junit["name"] = unit_name;
} else if (auto* convunit = unit->as<IfcSchema::IfcConversionBasedUnit>()) {
junit["name"] = convunit->Name();
junit["unitEnum"] = IfcSchema::IfcUnitEnum::ToString(convunit->UnitType());
if (convunit->ConversionFactor()) {
} else if (auto convunit = unit.concrete().as<IfcSchema::IfcConversionBasedUnit>()) {
junit["name"] = convunit.Name();
junit["unitEnum"] = IfcSchema::IfcUnitEnum::ToString(convunit.UnitType());
if (convunit.ConversionFactor()) {
json jconv;
auto val = convunit->ConversionFactor()->ValueComponent();
auto val = convunit.ConversionFactor().ValueComponent();
jconv["valueComponent"] = {
{"value", val->data().get_attribute_value(nullptr, nullptr, 0, 0).apply_visitor(format_value_visitor{})},
{"valueType", val->data().get_attribute_value(nullptr, nullptr, 0, 0).apply_visitor(get_type_visitor{})}
{"value", val.concrete().data()->get_attribute_value(0).apply_visitor(format_value_visitor{})},
{"valueType", val.concrete().data()->get_attribute_value(0).apply_visitor(get_type_visitor{})}
};
jconv["unitComponent"] = std::distance(units->begin(), std::find(units->begin(), units->end(), convunit->ConversionFactor()->UnitComponent()));
jconv["unitComponent"] = std::distance(units.begin(), std::find(units.begin(), units.end(), convunit.ConversionFactor().UnitComponent()));
junit["conversionFactor"] = jconv;
}
} else if (auto* derunit = unit->as<IfcSchema::IfcDerivedUnit>()) {
} else if (auto derunit = unit.concrete().as<IfcSchema::IfcDerivedUnit>()) {
#ifdef SCHEMA_IfcDerivedUnit_HAS_Name
// 4.3 onwards
if (derunit->Name()) {
junit["name"] = *derunit->Name();
if (derunit.Name()) {
junit["name"] = *derunit.Name();
}
#endif
json jelements = json::array();
auto elements = derunit->Elements();
for (auto& elem : *elements) {
auto elements = derunit.Elements();
for (auto& elem : elements) {
jelements.push_back({
{"unit", std::distance(units->begin(), std::find(units->begin(), units->end(), elem->Unit()))},
{"exponent", elem->Exponent()}
{"unit", std::distance(units.begin(), std::find(units.begin(), units.end(), elem.Unit()))},
{"exponent", elem.Exponent()}
});
}
junit["elements"] = jelements;
}
if (auto* namedunit = unit->as<IfcSchema::IfcNamedUnit>()) {
if (auto namedunit = unit.concrete().as<IfcSchema::IfcNamedUnit>()) {
// support for derived attributes is only available in python
if (namedunit->as<IfcSchema::IfcSIUnit>() == nullptr) {
if (auto* dimexp = namedunit->Dimensions()) {
if (!namedunit.as<IfcSchema::IfcSIUnit>()) {
if (auto dimexp = namedunit.Dimensions()) {
junit["dimensions"] = {
{"LengthExponent", dimexp->LengthExponent()},
{"MassExponent", dimexp->MassExponent()},
{"TimeExponent", dimexp->TimeExponent()},
{"ElectricCurrentExponent", dimexp->ElectricCurrentExponent()},
{"ThermodynamicTemperatureExponent", dimexp->ThermodynamicTemperatureExponent()},
{"AmountOfSubstanceExponent", dimexp->AmountOfSubstanceExponent()},
{"LuminousIntensityExponent", dimexp->LuminousIntensityExponent()}};
{"LengthExponent", dimexp.LengthExponent()},
{"MassExponent", dimexp.MassExponent()},
{"TimeExponent", dimexp.TimeExponent()},
{"ElectricCurrentExponent", dimexp.ElectricCurrentExponent()},
{"ThermodynamicTemperatureExponent", dimexp.ThermodynamicTemperatureExponent()},
{"AmountOfSubstanceExponent", dimexp.AmountOfSubstanceExponent()},
{"LuminousIntensityExponent", dimexp.LuminousIntensityExponent()}};
}
}
}
output["units"].push_back(junit);
}
auto project_units = project->UnitsInContext()->Units();
auto project_units = project.UnitsInContext().Units();
/*
{
"LENGTHUNIT": number,
@@ -536,11 +561,11 @@ void POSTFIX_SCHEMA(JsonSerializer)::finalize() {
"TIMEUNIT": number,
// ... other unit types
}*/
for (auto* pu : *project_units) {
auto it = std::find(units->begin(), units->end(), pu);
if (auto* nu = pu->as<IfcSchema::IfcNamedUnit>()) {
if (it != units->end()) {
output["projectUnits"][IfcSchema::IfcUnitEnum::ToString(nu->UnitType())] = std::distance(units->begin(), it);
for (auto pu : project_units) {
auto it = std::find(units.begin(), units.end(), pu);
if (auto nu = pu.as<IfcSchema::IfcNamedUnit>()) {
if (it != units.end()) {
output["projectUnits"][IfcSchema::IfcUnitEnum::ToString(nu.UnitType())] = std::distance(units.begin(), it);
}
}
}
@@ -569,294 +594,4 @@ void POSTFIX_SCHEMA(JsonSerializer)::finalize() {
f << output.dump(4);
}
/*
ptree root, header, units, decomposition, properties, quantities, types, layers, materials, work, calendars, connections, groups;
// Write the SPF header as XML nodes.
BOOST_FOREACH (const std::string& s, catch_exceptions([this]() { return file->header().file_description()->description(); })) {
header.add_child("file_description.description", ptree(s));
}
BOOST_FOREACH (const std::string& s, catch_exceptions([this]() { return file->header().file_name()->author(); })) {
header.add_child("file_name.author", ptree(s));
}
BOOST_FOREACH (const std::string& s, catch_exceptions([this]() { return file->header().file_name()->organization(); })) {
header.add_child("file_name.organization", ptree(s));
}
BOOST_FOREACH (const std::string& s, catch_exceptions([this]() { return file->header().file_schema()->schema_identifiers(); })) {
header.add_child("file_schema.schema_identifiers", ptree(s));
}
try {
header.put("file_description.implementation_level", file->header().file_description()->implementation_level());
} catch (const IfcParse::IfcException& ex) {
std::stringstream ss;
ss << "Failed to get ifc file header file_description implementation_level, error: '" << ex.what() << "'";
Logger::Message(Logger::LOG_ERROR, ss.str());
}
try {
header.put("file_name.name", file->header().file_name()->name());
} catch (const IfcParse::IfcException& ex) {
std::stringstream ss;
ss << "Failed to get ifc file header file_name name, error: '" << ex.what() << "'";
Logger::Message(Logger::LOG_ERROR, ss.str());
}
try {
header.put("file_name.time_stamp", file->header().file_name()->time_stamp());
} catch (const IfcParse::IfcException& ex) {
std::stringstream ss;
ss << "Failed to get ifc file header file_name time_stamp, error: '" << ex.what() << "'";
Logger::Message(Logger::LOG_ERROR, ss.str());
}
try {
header.put("file_name.preprocessor_version", file->header().file_name()->preprocessor_version());
} catch (const IfcParse::IfcException& ex) {
std::stringstream ss;
ss << "Failed to get ifc file header file_name preprocessor_version, error: '" << ex.what() << "'";
Logger::Message(Logger::LOG_ERROR, ss.str());
}
try {
header.put("file_name.originating_system", file->header().file_name()->originating_system());
} catch (const IfcParse::IfcException& ex) {
std::stringstream ss;
ss << "Failed to get ifc file header file_name originating_system, error: '" << ex.what() << "'";
Logger::Message(Logger::LOG_ERROR, ss.str());
}
try {
// @nb inconsistent spelling
header.put("file_name.authorization", file->header().file_name()->authorization());
} catch (const IfcParse::IfcException& ex) {
std::stringstream ss;
ss << "Failed to get ifc file header file_name authorization, error: '" << ex.what() << "'";
Logger::Message(Logger::LOG_ERROR, ss.str());
}
// Descend into the decomposition structure of the IFC file.
descend(mapping_, project, decomposition);
// Write all property sets and values as XML nodes.
IfcSchema::IfcPropertySet::list::ptr psets = file->instances_by_type<IfcSchema::IfcPropertySet>();
for (IfcSchema::IfcPropertySet::list::it it = psets->begin(); it != psets->end(); ++it) {
IfcSchema::IfcPropertySet* pset = *it;
ptree* node = format_entity_instance(mapping_, pset, properties);
if (node) {
format_properties(mapping_, pset->HasProperties(), *node);
}
}
// Write all group sets and values as XML nodes.
IfcSchema::IfcGroup::list::ptr gsets = file->instances_by_type<IfcSchema::IfcGroup>();
std::set<std::string> notRootGroups; //selfname, fathername
for (IfcSchema::IfcGroup::list::it it = gsets->begin(); it != gsets->end(); ++it) {
writeGroupToNode(mapping_, *it, groups, notRootGroups);
}
for (auto it = groups.begin(); it != groups.end();) {
if (notRootGroups.find(it->second.get<std::string>("<xmlattr>.Name")) != notRootGroups.end()) {
it = groups.erase(it);
} else {
it++;
}
}
// Write all quantities and values as XML nodes.
IfcSchema::IfcElementQuantity::list::ptr qtosets = file->instances_by_type<IfcSchema::IfcElementQuantity>();
for (IfcSchema::IfcElementQuantity::list::it it = qtosets->begin(); it != qtosets->end(); ++it) {
IfcSchema::IfcElementQuantity* qto = *it;
ptree* node = format_entity_instance(mapping_, qto, quantities);
if (node) {
format_quantities(mapping_, qto->Quantities(), *node);
}
}
// Write all work schedules and values as XML nodes.
ptree pwork_schedules;
IfcSchema::IfcWorkSchedule::list::ptr pschedules = file->instances_by_type<IfcSchema::IfcWorkSchedule>();
for (IfcSchema::IfcWorkSchedule::list::it it = pschedules->begin(); it != pschedules->end(); ++it) {
IfcSchema::IfcWorkSchedule* schedule = *it;
ptree* nschedule = format_entity_instance(mapping_, schedule, pwork_schedules);
if (nschedule) {
IfcSchema::IfcRelAssignsToControl::list::ptr controls = schedule->Controls();
for (IfcSchema::IfcRelAssignsToControl::list::it it2 = controls->begin(); it2 != controls->end(); ++it2) {
IfcSchema::IfcRelAssignsToControl* control = *it2;
IfcSchema::IfcObjectDefinition::list::ptr objects = control->RelatedObjects();
for (IfcSchema::IfcObjectDefinition::list::it it3 = objects->begin(); it3 != objects->end(); ++it3) {
IfcSchema::IfcObjectDefinition* object = *it3;
if (object && object->declaration().is(IfcSchema::IfcTask::Class())) {
IfcSchema::IfcTask* task = object->as<IfcSchema::IfcTask>();
format_tasks(mapping_, task, *nschedule);
}
}
}
}
}
work.add_child("schedules", pwork_schedules);
// Write all work plans and values as XML nodes.
ptree pwork_plans;
IfcSchema::IfcWorkPlan::list::ptr pplans = file->instances_by_type<IfcSchema::IfcWorkPlan>();
for (IfcSchema::IfcWorkPlan::list::it it = pplans->begin(); it != pplans->end(); ++it) {
IfcSchema::IfcWorkPlan* plan = *it;
ptree* nschedule = format_entity_instance(mapping_, plan, pwork_plans);
if (nschedule) {
#ifdef SCHEMA_IfcObjectDefinition_HAS_IsDecomposedBy
auto decomposed_by = plan->IsDecomposedBy();
for (auto it2 = decomposed_by->begin(); it2 != decomposed_by->end(); ++it2) {
IfcSchema::IfcObjectDefinition::list::ptr related_objects = (*it2)->RelatedObjects();
for (IfcSchema::IfcObjectDefinition::list::it it3 = related_objects->begin(); it3 != related_objects->end(); ++it3) {
IfcSchema::IfcObjectDefinition* work_schedule = *it3;
ptree pwork_schedule;
pwork_schedule.put("<xmlattr>.id", work_schedule->GlobalId());
nschedule->add_child("IfcWorkSchedule", pwork_schedule);
}
}
#endif
}
}
work.add_child("plans", pwork_plans);
// Write all work calendars and values as XML nodes.
#ifdef SCHEMA_HAS_IfcWorkCalendar
IfcSchema::IfcWorkCalendar::list::ptr pcalendars = file->instances_by_type<IfcSchema::IfcWorkCalendar>();
for (IfcSchema::IfcWorkCalendar::list::it it = pcalendars->begin(); it != pcalendars->end(); ++it) {
IfcSchema::IfcWorkCalendar* calendar = *it;
ptree* ncalendar = format_entity_instance(mapping_, calendar, calendars);
if (ncalendar) {
IfcSchema::IfcWorkTime::list::ptr working_times = calendar->WorkingTimes().value_or(nullptr);
if (working_times != nullptr) {
for (IfcSchema::IfcWorkTime::list::it it2 = working_times->begin(); it2 != working_times->end(); ++it2) {
IfcSchema::IfcWorkTime* working_time = *it2;
format_entity_instance(mapping_, working_time, *ncalendar);
}
}
}
}
#endif
IfcSchema::IfcRelConnectsElements::list::ptr pconnections = file->instances_by_type<IfcSchema::IfcRelConnectsElements>();
for (IfcSchema::IfcRelConnectsElements::list::it it = pconnections->begin(); it != pconnections->end(); ++it) {
IfcSchema::IfcRelConnectsElements* connection = *it;
ptree* nconnection = format_entity_instance(mapping_, connection, connections);
ptree nrelatedElement;
ptree nrelatingElement;
format_entity_instance(mapping_, connection->RelatedElement(), nrelatedElement, true);
format_entity_instance(mapping_, connection->RelatingElement(), nrelatingElement, true);
nconnection->add_child("RelatedElement", nrelatedElement);
nconnection->add_child("RelatingElement", nrelatingElement);
}
// Write all type objects as XML nodes.
IfcSchema::IfcTypeObject::list::ptr type_objects = file->instances_by_type<IfcSchema::IfcTypeObject>();
for (IfcSchema::IfcTypeObject::list::it it = type_objects->begin(); it != type_objects->end(); ++it) {
IfcSchema::IfcTypeObject* type_object = *it;
ptree* node = descend(mapping_, type_object, types);
if (node && type_object->HasPropertySets()) {
IfcSchema::IfcPropertySetDefinition::list::ptr property_sets = *type_object->HasPropertySets();
for (IfcSchema::IfcPropertySetDefinition::list::it jt = property_sets->begin(); jt != property_sets->end(); ++jt) {
IfcSchema::IfcPropertySetDefinition* pset = *jt;
if (pset->declaration().is(IfcSchema::IfcPropertySet::Class())) {
format_entity_instance(mapping_, pset, *node, true);
}
}
}
}
// Write all assigned units as XML nodes.
auto unit_assignments = project->UnitsInContext()->Units();
for (auto it = unit_assignments->begin(); it != unit_assignments->end(); ++it) {
if ((*it)->declaration().is(IfcSchema::IfcNamedUnit::Class())) {
IfcSchema::IfcNamedUnit* named_unit = (*it)->as<IfcSchema::IfcNamedUnit>();
ptree* node = format_entity_instance(mapping_, named_unit, units);
if (node) {
node->put("<xmlattr>.SI_equivalent", IfcParse::get_SI_equivalent<IfcSchema>(named_unit));
}
} else if ((*it)->declaration().is(IfcSchema::IfcMonetaryUnit::Class())) {
format_entity_instance(mapping_, (*it)->as<IfcSchema::IfcMonetaryUnit>(), units);
}
}
// Layer assignments. IfcPresentationLayerAssignments don't have GUIDs (only optional Identifier)
// so use names as the IDs and only insert those with unique names. In case of possible duplicate names/IDs
// the first IfcPresentationLayerAssignment occurrence takes precedence.
std::set<std::string> layer_names;
IfcSchema::IfcPresentationLayerAssignment::list::ptr layer_assignments = file->instances_by_type<IfcSchema::IfcPresentationLayerAssignment>();
for (IfcSchema::IfcPresentationLayerAssignment::list::it it = layer_assignments->begin(); it != layer_assignments->end(); ++it) {
const std::string& name = (*it)->Name();
if (layer_names.find(name) == layer_names.end()) {
layer_names.insert(name);
ptree node;
node.put("<xmlattr>.id", name);
format_entity_instance(mapping_, *it, node, layers);
}
}
IfcSchema::IfcRelAssociatesMaterial::list::ptr materal_associations = file->instances_by_type<IfcSchema::IfcRelAssociatesMaterial>();
std::set<IfcSchema::IfcMaterialSelect*> emitted_materials;
for (IfcSchema::IfcRelAssociatesMaterial::list::it it = materal_associations->begin(); it != materal_associations->end(); ++it) {
IfcSchema::IfcMaterialSelect* mat = (**it).RelatingMaterial();
if (emitted_materials.find(mat) == emitted_materials.end()) {
emitted_materials.insert(mat);
ptree node;
node.put("<xmlattr>.id", qualify_unrooted_instance(mat));
if (mat->as<IfcSchema::IfcMaterialLayerSetUsage>() || mat->as<IfcSchema::IfcMaterialLayerSet>()) {
IfcSchema::IfcMaterialLayerSet* layerset = mat->as<IfcSchema::IfcMaterialLayerSet>();
if (!layerset) {
layerset = mat->as<IfcSchema::IfcMaterialLayerSetUsage>()->ForLayerSet();
}
if (layerset->LayerSetName()) {
node.put("<xmlattr>.LayerSetName", *layerset->LayerSetName());
}
IfcSchema::IfcMaterialLayer::list::ptr ls = layerset->MaterialLayers();
for (IfcSchema::IfcMaterialLayer::list::it jt = ls->begin(); jt != ls->end(); ++jt) {
ptree subnode;
if ((*jt)->Material()) {
subnode.put("<xmlattr>.Name", (*jt)->Material()->Name());
}
format_entity_instance(mapping_, *jt, subnode, node);
}
} else if (mat->as<IfcSchema::IfcMaterialList>()) {
IfcSchema::IfcMaterial::list::ptr mats = mat->as<IfcSchema::IfcMaterialList>()->Materials();
for (IfcSchema::IfcMaterial::list::it jt = mats->begin(); jt != mats->end(); ++jt) {
ptree subnode;
format_entity_instance(mapping_, *jt, subnode, node);
}
}
format_entity_instance(mapping_, mat->as<IfcUtil::IfcBaseEntity>(), node, materials);
}
}
root.add_child("ifc.header", header);
root.add_child("ifc.units", units);
root.add_child("ifc.connections", connections);
root.add_child("ifc.properties", properties);
root.add_child("ifc.quantities", quantities);
root.add_child("ifc.work", work);
root.add_child("ifc.calendars", calendars);
root.add_child("ifc.types", types);
root.add_child("ifc.layers", layers);
root.add_child("ifc.groups", groups);
root.add_child("ifc.materials", materials);
root.add_child("ifc.decomposition", decomposition);
root.put("ifc.<xmlattr>.xmlns:xlink", "http://www.w3.org/1999/xlink");
#if BOOST_VERSION >= 105600
boost::property_tree::xml_writer_settings<ptree::key_type> settings = boost::property_tree::xml_writer_make_settings<ptree::key_type>('\t', 1);
#else
boost::property_tree::xml_writer_settings<char> settings('\t', 1);
#endif
std::ofstream f(IfcUtil::path::from_utf8(xml_filename).c_str());
boost::property_tree::write_xml(f, root, settings);
*/
#endif
+246 -270
View File
@@ -57,8 +57,8 @@ std::map<std::string, std::string> POSTFIX_SCHEMA(argument_name_map);
// Format an IFC attribute and maybe returns as string. Only literal scalar
// values are converted. Things like entity instances and lists are omitted.
boost::optional<std::string> format_attribute(ifcopenshell::geometry::abstract_mapping* mapping, AttributeValue argument, IfcUtil::ArgumentType argument_type, const std::string& argument_name) {
boost::optional<std::string> value;
std::optional<std::string> format_attribute(ifcopenshell::geometry::abstract_mapping* mapping, AttributeValue argument, IfcUtil::ArgumentType argument_type, const std::string& argument_name) {
std::optional<std::string> value;
// Hard-code lat-lon as it represents an array
// of integers best emitted as a single decimal
@@ -104,29 +104,27 @@ boost::optional<std::string> format_attribute(ifcopenshell::geometry::abstract_m
value = stream.str();
break; }
case IfcUtil::Argument_ENTITY_INSTANCE: {
IfcUtil::IfcBaseClass* e = argument;
if (!e->declaration().as_entity()) {
IfcUtil::IfcBaseType* f = e->as<IfcUtil::IfcBaseType>();
value = format_attribute(mapping, f->get_attribute_value(0), f->get_attribute_value(0).type(), argument_name);
} else if (e->declaration().is(IfcSchema::IfcSIUnit::Class()) || e->declaration().is(IfcSchema::IfcConversionBasedUnit::Class())) {
express::Base e = argument;
if (e.declaration().as_entity() == nullptr) {
auto f = e.as<express::DeclaredType>();
value = format_attribute(mapping, f.get_attribute_value(0), f.get_attribute_value(0).type(), argument_name);
} else if (e.declaration().is(IfcSchema::IfcSIUnit::Class()) || e.declaration().is(IfcSchema::IfcConversionBasedUnit::Class())) {
// Some string concatenation to have a unit name as a XML attribute.
std::string unit_name;
if (e->declaration().is(IfcSchema::IfcSIUnit::Class())) {
IfcSchema::IfcSIUnit* unit = e->as<IfcSchema::IfcSIUnit>();
unit_name = IfcSchema::IfcSIUnitName::ToString(unit->Name());
if (unit->Prefix()) {
unit_name = IfcSchema::IfcSIPrefix::ToString(*unit->Prefix()) + unit_name;
if (auto unit = e.as<IfcSchema::IfcSIUnit>()) {
unit_name = IfcSchema::IfcSIUnitName::ToString(unit.Name());
if (unit.Prefix()) {
unit_name = IfcSchema::IfcSIPrefix::ToString(*unit.Prefix()) + unit_name;
}
} else {
IfcSchema::IfcConversionBasedUnit* unit = e->as<IfcSchema::IfcConversionBasedUnit>();
unit_name = unit->Name();
auto cunit = e.as<IfcSchema::IfcConversionBasedUnit>();
unit_name = cunit.Name();
}
value = unit_name;
} else if (e->declaration().is(IfcSchema::IfcLocalPlacement::Class())) {
IfcSchema::IfcLocalPlacement* placement = e->as<IfcSchema::IfcLocalPlacement>();
} else if (auto placement = e.as<IfcSchema::IfcLocalPlacement>()) {
auto item = mapping->map(e);
auto matrix = ifcopenshell::geometry::taxonomy::cast< ifcopenshell::geometry::taxonomy::matrix4>(item);
@@ -151,28 +149,28 @@ boost::optional<std::string> format_attribute(ifcopenshell::geometry::abstract_m
}
// Appends to a node with possibly existing attributes
ptree* format_entity_instance(ifcopenshell::geometry::abstract_mapping* mapping, IfcUtil::IfcBaseEntity* instance, ptree& child, ptree& tree, bool as_link = false) {
const unsigned n = instance->declaration().as_entity()->attribute_count();
ptree* format_entity_instance(ifcopenshell::geometry::abstract_mapping* mapping, const express::Base& instance, ptree& child, ptree& tree, bool as_link = false) {
const unsigned n = instance.declaration().as_entity()->attribute_count();
for (unsigned i = 0; i < n; ++i) {
try {
instance->get_attribute_value(i);
instance.get_attribute_value(i);
} catch (const std::exception&) {
Logger::Error("Expected " + boost::lexical_cast<std::string>(n) + " attributes for:", instance);
break;
}
auto argument = instance->get_attribute_value(i);
auto argument = instance.get_attribute_value(i);
if (argument.isNull()) continue;
std::string argument_name = instance->declaration().as_entity()->attribute_by_index(i)->name();
std::string argument_name = instance.declaration().as_entity()->attribute_by_index(i)->name();
std::map<std::string, std::string>::const_iterator argument_name_it;
argument_name_it = POSTFIX_SCHEMA(argument_name_map).find(argument_name);
if (argument_name_it != POSTFIX_SCHEMA(argument_name_map).end()) {
argument_name = argument_name_it->second;
}
const IfcUtil::ArgumentType argument_type = instance->get_attribute_value(i).type();
const IfcUtil::ArgumentType argument_type = instance.get_attribute_value(i).type();
const std::string qualified_name = instance->declaration().name() + "." + argument_name;
boost::optional<std::string> value;
const std::string qualified_name = instance.declaration().name() + "." + argument_name;
std::optional<std::string> value;
try {
value = format_attribute(mapping, argument, argument_type, qualified_name);
} catch (const std::exception& e) {
@@ -191,26 +189,26 @@ ptree* format_entity_instance(ifcopenshell::geometry::abstract_mapping* mapping,
}
}
}
return &tree.add_child(instance->declaration().name(), child);
return &tree.add_child(instance.declaration().name(), child);
}
// Formats an entity instances as a ptree node, and insert into the DOM. Recurses
// over the entity attributes and writes them as xml attributes of the node.
ptree* format_entity_instance(ifcopenshell::geometry::abstract_mapping* mapping, IfcUtil::IfcBaseEntity* instance, ptree& tree, bool as_link = false) {
ptree* format_entity_instance(ifcopenshell::geometry::abstract_mapping* mapping, const express::Base& instance, ptree& tree, bool as_link = false) {
ptree child;
return format_entity_instance(mapping, instance, child, tree, as_link);
}
std::string qualify_unrooted_instance(IfcUtil::IfcBaseInterface* inst) {
return inst->declaration().name() + "_" + boost::lexical_cast<std::string>(inst->as<IfcUtil::IfcBaseEntity>()->id());
std::string qualify_unrooted_instance(const express::Base& inst) {
return inst.declaration().name() + "_" + std::to_string(inst.id());
}
// A function to be called recursively. Template specialization is used
// to descend into decomposition, containment and property relationships.
template <typename A>
ptree* descend(ifcopenshell::geometry::abstract_mapping* mapping, A* instance, ptree& tree, IfcUtil::IfcBaseClass* parent=nullptr) {
if (instance->declaration().is(IfcSchema::IfcObjectDefinition::Class())) {
return descend(mapping, instance->template as<IfcSchema::IfcObjectDefinition>(), tree, parent);
ptree* descend(ifcopenshell::geometry::abstract_mapping* mapping, A instance, ptree& tree, express::Base parent = express::Base()) {
if (instance.declaration().is(IfcSchema::IfcObjectDefinition::Class())) {
return descend(mapping, instance.template as<IfcSchema::IfcObjectDefinition>(), tree, parent);
} else {
return format_entity_instance(mapping, instance, tree);
}
@@ -219,13 +217,27 @@ ptree* descend(ifcopenshell::geometry::abstract_mapping* mapping, A* instance, p
// Returns related entity instances using IFC's objectified relationship
// model. The second and third argument require a member function pointer.
template <typename T, typename U, typename V, typename F, typename G>
auto get_related(T* t, F f, G g) {
typename U::list::ptr li = (*t.*f)()->template as<U>();
typename aggregate_of<V>::ptr acc(new aggregate_of<V>);
for (typename U::list::it it = li->begin(); it != li->end(); ++it) {
U* u = *it;
auto get_related(T t, F f, G g) {
auto li = (t.*f)();
std::vector<V> acc;
for (auto& u : li) {
try {
acc->push((*u.*g)()->template as<V>());
auto vs = (u.as<U>().*g)();
if constexpr (std::is_base_of_v<express::Base, decltype(vs)>) {
if (auto vv = vs.as<V>()) {
acc.push_back(vv);
}
} else if constexpr (std::is_base_of_v<express::Select, decltype(vs)>) {
if (auto vv = vs.concrete().as<V>()) {
acc.push_back(vv);
}
} else {
for (auto& v : vs) {
if (auto vv = v.as<V>()) {
acc.push_back(vv);
}
}
}
} catch (IfcParse::IfcException& e) {
Logger::Error(e);
}
@@ -236,10 +248,10 @@ auto get_related(T* t, F f, G g) {
// Descends into the tree by recursing into IfcRelContainedInSpatialStructure,
// IfcRelDecomposes, IfcRelDefinesByType, IfcRelDefinesByProperties relations.
template <>
ptree* descend(ifcopenshell::geometry::abstract_mapping* mapping, IfcSchema::IfcObjectDefinition* product, ptree& tree, IfcUtil::IfcBaseClass* parent) {
if (product->declaration().is(IfcSchema::IfcElement::Class())) {
auto voids = product->as<IfcSchema::IfcElement>()->FillsVoids();
if (voids && voids->size() == 1 && (*voids->begin())->RelatingOpeningElement() != parent) {
ptree* descend(ifcopenshell::geometry::abstract_mapping* mapping, const IfcSchema::IfcObjectDefinition& product, ptree& tree, express::Base parent) {
if (product.declaration().is(IfcSchema::IfcElement::Class())) {
auto voids = product.as<IfcSchema::IfcElement>().FillsVoids();
if (voids.size() == 1 && voids.front().RelatingOpeningElement() != parent) {
// Fills are placed under their corresponding opening, return early to avoid duplication.
return nullptr;
}
@@ -247,125 +259,119 @@ ptree* descend(ifcopenshell::geometry::abstract_mapping* mapping, IfcSchema::Ifc
ptree& child = *format_entity_instance(mapping, product, tree);
if (product->declaration().is(IfcSchema::IfcOpeningElement::Class())) {
IfcSchema::IfcOpeningElement* opening = product->as<IfcSchema::IfcOpeningElement>();
IfcSchema::IfcElement::list::ptr fills = get_related<IfcSchema::IfcOpeningElement, IfcSchema::IfcRelFillsElement, IfcSchema::IfcElement>(
if (auto opening = product.as<IfcSchema::IfcOpeningElement>()) {
auto fills = get_related<IfcSchema::IfcOpeningElement, IfcSchema::IfcRelFillsElement, IfcSchema::IfcElement>(
opening, &IfcSchema::IfcOpeningElement::HasFillings, &IfcSchema::IfcRelFillsElement::RelatedBuildingElement);
for (IfcSchema::IfcElement::list::it it = fills->begin(); it != fills->end(); ++it) {
descend(mapping, *it, child, product);
for (auto& f : fills) {
descend(mapping, f, child, product);
}
}
if (product->declaration().is(IfcSchema::IfcSpatialStructureElement::Class())) {
IfcSchema::IfcSpatialStructureElement* structure = product->as<IfcSchema::IfcSpatialStructureElement>();
IfcSchema::IfcObjectDefinition::list::ptr elements = get_related
if (auto structure = product.as<IfcSchema::IfcSpatialStructureElement>()) {
auto elements = get_related
<IfcSchema::IfcSpatialStructureElement, IfcSchema::IfcRelContainedInSpatialStructure, IfcSchema::IfcObjectDefinition>
(structure, &IfcSchema::IfcSpatialStructureElement::ContainsElements, &IfcSchema::IfcRelContainedInSpatialStructure::RelatedElements);
for (IfcSchema::IfcObjectDefinition::list::it it = elements->begin(); it != elements->end(); ++it) {
descend(mapping, *it, child, product);
for (auto& el : elements) {
descend(mapping, el, child, product);
}
}
if (product->declaration().is(IfcSchema::IfcElement::Class())) {
IfcSchema::IfcElement* element = static_cast<IfcSchema::IfcElement*>(product);
IfcSchema::IfcOpeningElement::list::ptr openings = get_related<IfcSchema::IfcElement, IfcSchema::IfcRelVoidsElement, IfcSchema::IfcOpeningElement>(
if (auto element = product.as<IfcSchema::IfcElement>()) {
auto openings = get_related<IfcSchema::IfcElement, IfcSchema::IfcRelVoidsElement, IfcSchema::IfcOpeningElement>(
element, &IfcSchema::IfcElement::HasOpenings, &IfcSchema::IfcRelVoidsElement::RelatedOpeningElement);
for (IfcSchema::IfcOpeningElement::list::it it = openings->begin(); it != openings->end(); ++it) {
descend(mapping, *it, child, product);
for (auto& op : openings) {
descend(mapping, op, child, product);
}
}
#ifdef SCHEMA_IfcRelDecomposes_HAS_RelatedObjects
IfcSchema::IfcObjectDefinition::list::ptr structures = get_related
auto structures = get_related
<IfcSchema::IfcObjectDefinition, IfcSchema::IfcRelDecomposes, IfcSchema::IfcObjectDefinition>
(product, &IfcSchema::IfcObjectDefinition::IsDecomposedBy, &IfcSchema::IfcRelDecomposes::RelatedObjects);
#else
IfcSchema::IfcObjectDefinition::list::ptr structures = get_related
auto structures = get_related
<IfcSchema::IfcObjectDefinition, IfcSchema::IfcRelAggregates, IfcSchema::IfcObjectDefinition>
(product, &IfcSchema::IfcObjectDefinition::IsDecomposedBy, &IfcSchema::IfcRelAggregates::RelatedObjects);
structures->push(get_related
auto nested = get_related
<IfcSchema::IfcObjectDefinition, IfcSchema::IfcRelNests, IfcSchema::IfcObjectDefinition>
(product, &IfcSchema::IfcObjectDefinition::IsNestedBy, &IfcSchema::IfcRelNests::RelatedObjects));
(product, &IfcSchema::IfcObjectDefinition::IsNestedBy, &IfcSchema::IfcRelNests::RelatedObjects);
structures.insert(structures.end(), nested.begin(), nested.end());
#endif
for (IfcSchema::IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
IfcSchema::IfcObjectDefinition* ob = *it;
for (auto& ob : structures) {
descend(mapping, ob, child, product);
}
if (product->declaration().is(IfcSchema::IfcObject::Class())) {
IfcSchema::IfcObject* object = product->as<IfcSchema::IfcObject>();
IfcSchema::IfcPropertySetDefinition::list::ptr property_sets = get_related
if (auto object = product.as<IfcSchema::IfcObject>()) {
auto property_sets = get_related
<IfcSchema::IfcObject, IfcSchema::IfcRelDefinesByProperties, IfcSchema::IfcPropertySetDefinition>
(object, &IfcSchema::IfcObject::IsDefinedBy, &IfcSchema::IfcRelDefinesByProperties::RelatingPropertyDefinition);
#ifdef SCHEMAS_HAS_IfcPropertySetDefinitionSet
aggregate_of<IfcSchema::IfcPropertySetDefinitionSet>::ptr property_set_sets = get_related
auto property_set_sets = get_related
<IfcSchema::IfcObject, IfcSchema::IfcRelDefinesByProperties, IfcSchema::IfcPropertySetDefinitionSet>
(object, &IfcSchema::IfcObject::IsDefinedBy, &IfcSchema::IfcRelDefinesByProperties::RelatingPropertyDefinition);
for (auto& s : *property_set_sets) {
property_sets->push((decltype(property_sets))*s);
for (auto& s : property_set_sets) {
auto set_sets_value = (decltype(property_sets))s;
property_sets.insert(property_sets.end(), set_sets_value.begin(), set_sets_value.end());
}
#endif
for (IfcSchema::IfcPropertySetDefinition::list::it it = property_sets->begin(); it != property_sets->end(); ++it) {
IfcSchema::IfcPropertySetDefinition* pset = *it;
if (pset->declaration().is(IfcSchema::IfcPropertySet::Class())) {
for (auto& pset : property_sets) {
if (pset.declaration().is(IfcSchema::IfcPropertySet::Class())) {
format_entity_instance(mapping, pset, child, true);
} else if (pset->declaration().is(IfcSchema::IfcElementQuantity::Class())) {
} else if (pset.declaration().is(IfcSchema::IfcElementQuantity::Class())) {
format_entity_instance(mapping, pset, child, true);
}
}
#ifdef SCHEMA_IfcObject_HAS_IsTypedBy
IfcSchema::IfcTypeObject::list::ptr types = get_related
auto types = get_related
<IfcSchema::IfcObject, IfcSchema::IfcRelDefinesByType, IfcSchema::IfcTypeObject>
(object, &IfcSchema::IfcObject::IsTypedBy, &IfcSchema::IfcRelDefinesByType::RelatingType);
#else
IfcSchema::IfcTypeObject::list::ptr types = get_related
auto types = get_related
<IfcSchema::IfcObject, IfcSchema::IfcRelDefinesByType, IfcSchema::IfcTypeObject>
(object, &IfcSchema::IfcObject::IsDefinedBy, &IfcSchema::IfcRelDefinesByType::RelatingType);
#endif
for (IfcSchema::IfcTypeObject::list::it it = types->begin(); it != types->end(); ++it) {
IfcSchema::IfcTypeObject* type = *it;
for (auto& type : types) {
format_entity_instance(mapping, type, child, true);
}
}
if (product->declaration().is(IfcSchema::IfcProduct::Class())) {
std::map<std::string, IfcUtil::IfcBaseEntity*> layers = mapping->get_layers(product);
for (std::map<std::string, IfcUtil::IfcBaseEntity*>::const_iterator it = layers.begin(); it != layers.end(); ++it) {
if (product.declaration().is(IfcSchema::IfcProduct::Class())) {
auto layers = mapping->get_layers(product);
for (auto& p : layers) {
// IfcPresentationLayerAssignments don't have GUIDs (only optional Identifier) so use name as the ID.
// Note that the IfcPresentationLayerAssignment passed here doesn't really matter as as_link is true
// for the format_entity_instance() call.
ptree node;
node.put("<xmlattr>.xlink:href", "#" + it->first);
format_entity_instance(mapping, it->second, node, child, true);
node.put("<xmlattr>.xlink:href", "#" + p.first);
format_entity_instance(mapping, p.second, node, child, true);
}
IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations();
for (IfcSchema::IfcRelAssociates::list::it it = associations->begin(); it != associations->end(); ++it) {
if ((*it)->as<IfcSchema::IfcRelAssociatesMaterial>()) {
IfcSchema::IfcMaterialSelect* mat = (*it)->as<IfcSchema::IfcRelAssociatesMaterial>()->RelatingMaterial();
auto associations = product.HasAssociations();
for (auto& rel : associations) {
if (auto relmat = rel.as<IfcSchema::IfcRelAssociatesMaterial>()) {
IfcSchema::IfcMaterialSelect mat = relmat.RelatingMaterial();
ptree node;
node.put("<xmlattr>.xlink:href", "#" + qualify_unrooted_instance(mat));
format_entity_instance(mapping, mat->as<IfcUtil::IfcBaseEntity>(), node, child, true);
format_entity_instance(mapping, mat.concrete(), node, child, true);
}
}
}
#if defined(SCHEMA_HAS_IfcAlignmentSegment) && defined(SCHEMA_IfcAlignmentSegment_HAS_DesignParameters)
if (auto* als = product->as<IfcSchema::IfcAlignmentSegment>()) {
if (auto als = product.as<IfcSchema::IfcAlignmentSegment>()) {
ptree node;
format_entity_instance(mapping, als->DesignParameters(), node, child, false);
format_entity_instance(mapping, als.DesignParameters(), node, child, false);
}
#endif
@@ -373,42 +379,38 @@ ptree* descend(ifcopenshell::geometry::abstract_mapping* mapping, IfcSchema::Ifc
}
// Format IfcProperty instances and insert into the DOM. IfcComplexProperties are flattened out.
void format_properties(ifcopenshell::geometry::abstract_mapping* mapping, IfcSchema::IfcProperty::list::ptr properties, ptree& node) {
for (IfcSchema::IfcProperty::list::it it = properties->begin(); it != properties->end(); ++it) {
IfcSchema::IfcProperty* p = *it;
if (p->declaration().is(IfcSchema::IfcComplexProperty::Class())) {
IfcSchema::IfcComplexProperty* complex = p->as<IfcSchema::IfcComplexProperty>();
format_properties(mapping, complex->HasProperties(), node);
void format_properties(ifcopenshell::geometry::abstract_mapping* mapping, const std::vector<IfcSchema::IfcProperty>& properties, ptree& node) {
for (auto& p : properties) {
if (auto complex = p.as<IfcSchema::IfcComplexProperty>()) {
format_properties(mapping, complex.HasProperties(), node);
} else {
format_entity_instance(mapping, p, node);
}
}
}
void writeGroupToNode(ifcopenshell::geometry::abstract_mapping* mapping, IfcSchema::IfcGroup* group, ptree& node, std::set<std::string>notRootGroups) {
void writeGroupToNode(ifcopenshell::geometry::abstract_mapping* mapping, IfcSchema::IfcGroup group, ptree& node, std::set<std::string> notRootGroups) {
// @todo tfk: instead of a set<string> shouldn't we just have a set<IfcGroup>, the current approach
// might not work with non-unique or NIL group names.
// @todo tfk: should the set be a passed as a reference?
if (!group->Name()) {
if (!group.Name()) {
return;
}
if (notRootGroups.find(*group->Name()) != notRootGroups.end()) {
if (notRootGroups.find(*group.Name()) != notRootGroups.end()) {
return;
}
// Write one group to root
ptree* node2 = descend(mapping, group, node);
auto father = group->IsGroupedBy();
for (auto iter = father->begin(); iter != father->end(); iter++)
auto father = group.IsGroupedBy();
for (auto& ii : father)
{
IfcSchema::IfcRelAssigns* ii = *iter;
auto objs = ii->RelatedObjects();
for (auto objit = objs->begin(); objit != objs->end(); objit++) {
auto entity = *objit;
if (entity->declaration().is(IfcSchema::IfcGroup::Class()) && entity->Name()) {
writeGroupToNode(mapping, entity->as<IfcSchema::IfcGroup>(), *node2, notRootGroups);
notRootGroups.emplace(*entity->Name());
auto objs = ii.RelatedObjects();
for (auto entity : objs) {
if (entity.as<IfcSchema::IfcGroup>() && entity.Name()) {
writeGroupToNode(mapping, entity.as<IfcSchema::IfcGroup>(), *node2, notRootGroups);
notRootGroups.emplace(*entity.Name());
}
else {
// Write child to father group
@@ -419,24 +421,22 @@ void writeGroupToNode(ifcopenshell::geometry::abstract_mapping* mapping, IfcSche
}
// Format IfcElementQuantity instances and insert into the DOM.
void format_quantities(ifcopenshell::geometry::abstract_mapping* mapping, IfcSchema::IfcPhysicalQuantity::list::ptr quantities, ptree& node) {
for (IfcSchema::IfcPhysicalQuantity::list::it it = quantities->begin(); it != quantities->end(); ++it) {
IfcSchema::IfcPhysicalQuantity* p = *it;
void format_quantities(ifcopenshell::geometry::abstract_mapping* mapping, const std::vector<IfcSchema::IfcPhysicalQuantity>& quantities, ptree& node) {
for (auto& p : quantities) {
ptree* node2 = format_entity_instance(mapping, p, node);
if (node2 && p->declaration().is(IfcSchema::IfcPhysicalComplexQuantity::Class())) {
IfcSchema::IfcPhysicalComplexQuantity* complex = p->as<IfcSchema::IfcPhysicalComplexQuantity>();
format_quantities(mapping, complex->HasQuantities(), *node2);
if (node2 && p.declaration().is(IfcSchema::IfcPhysicalComplexQuantity::Class())) {
format_quantities(mapping, p.as<IfcSchema::IfcPhysicalComplexQuantity>().HasQuantities(), *node2);
}
}
}
// Format IfcTask instances and insert into the DOM.
void format_tasks(ifcopenshell::geometry::abstract_mapping* mapping, IfcSchema::IfcTask* task, ptree& node) {
void format_tasks(ifcopenshell::geometry::abstract_mapping* mapping, IfcSchema::IfcTask task, ptree& node) {
ptree* ntask = format_entity_instance(mapping, task, node);
if (ntask) {
#ifdef SCHEMA_IfcTask_HAS_TaskTime
IfcSchema::IfcTaskTime* task_time = task->TaskTime();
IfcSchema::IfcTaskTime task_time = task.TaskTime();
if (task_time)
{
format_entity_instance(mapping, task_time, *ntask);
@@ -444,101 +444,94 @@ void format_tasks(ifcopenshell::geometry::abstract_mapping* mapping, IfcSchema::
#endif
#ifdef SCHEMA_IfcProcess_HAS_IsSuccessorFrom
IfcSchema::IfcRelSequence::list::ptr successor_from = task->IsSuccessorFrom();
for (IfcSchema::IfcRelSequence::list::it it = successor_from->begin(); it != successor_from->end(); ++it)
auto successor_from = task.IsSuccessorFrom();
for (auto& rel : successor_from)
{
IfcSchema::IfcProcess* relating_process = (*it)->RelatingProcess();
IfcSchema::IfcProcess relating_process = rel.RelatingProcess();
ptree nobject;
nobject.put("<xmlattr>.id", relating_process->GlobalId());
nobject.put("<xmlattr>.id", relating_process.GlobalId());
ntask->add_child("IsSuccessorFrom", nobject);
}
#endif
#ifdef SCHEMA_IfcProcess_HAS_IsPredecessorTo
IfcSchema::IfcRelSequence::list::ptr predecessor_to = task->IsPredecessorTo();
for (IfcSchema::IfcRelSequence::list::it it = predecessor_to->begin(); it != predecessor_to->end(); ++it)
auto predecessor_to = task.IsPredecessorTo();
for (auto& rel : predecessor_to)
{
IfcSchema::IfcProcess* relating_process = (*it)->RelatedProcess();
IfcSchema::IfcProcess relating_process = rel.RelatedProcess();
ptree nobject;
nobject.put("<xmlattr>.id", relating_process->GlobalId());
nobject.put("<xmlattr>.id", relating_process.GlobalId());
ntask->add_child("IsPredecessorTo", nobject);
}
#endif
IfcSchema::IfcPropertySetDefinition::list::ptr property_sets = get_related
auto property_sets = get_related
<IfcSchema::IfcObject, IfcSchema::IfcRelDefinesByProperties, IfcSchema::IfcPropertySetDefinition>
(task, &IfcSchema::IfcObject::IsDefinedBy, &IfcSchema::IfcRelDefinesByProperties::RelatingPropertyDefinition);
for (IfcSchema::IfcPropertySetDefinition::list::it it = property_sets->begin(); it != property_sets->end(); ++it) {
IfcSchema::IfcPropertySetDefinition* pset = *it;
if (pset->declaration().is(IfcSchema::IfcPropertySet::Class())) {
for (auto& pset : property_sets) {
if (pset.declaration().is(IfcSchema::IfcPropertySet::Class())) {
format_entity_instance(mapping, pset, *ntask, true);
}
else if (pset->declaration().is(IfcSchema::IfcElementQuantity::Class())) {
else if (pset.declaration().is(IfcSchema::IfcElementQuantity::Class())) {
format_entity_instance(mapping, pset, *ntask, true);
}
}
#ifdef SCHEMA_IfcProcess_HAS_OperatesOn
IfcSchema::IfcRelAssignsToProcess::list::ptr operates = task->OperatesOn();
if (operates->size() > 0)
auto operates = task.OperatesOn();
for (auto& operation : operates)
{
for (IfcSchema::IfcRelAssignsToProcess::list::it i = operates->begin(); i != operates->end(); ++i)
auto objects = operation.RelatedObjects();
for (auto& object : objects)
{
IfcSchema::IfcRelAssignsToProcess* operation = (*i);
IfcSchema::IfcObjectDefinition::list::ptr objects = operation->RelatedObjects();
for (IfcSchema::IfcObjectDefinition::list::it it2 = objects->begin(); it2 != objects->end(); ++it2)
ptree nobject;
nobject.put("<xmlattr>.id", object.GlobalId());
if (object.declaration().is(IfcSchema::IfcProduct::Class()))
{
IfcSchema::IfcObjectDefinition* object = *it2;
ptree nobject;
nobject.put("<xmlattr>.id", object->GlobalId());
if (object->declaration().is(IfcSchema::IfcProduct::Class()))
{
ntask->add_child("Input", nobject);
}
else if (object->declaration().is(IfcSchema::IfcResource::Class()))
{
ntask->add_child("Resource", nobject);
}
else if (object->declaration().is(IfcSchema::IfcControl::Class()))
{
ntask->add_child("Control", nobject);
}
else
{
nobject.put("<xmlattr>.Type", object->declaration().name());
ntask->add_child("OperatesOn", nobject);
}
ntask->add_child("Input", nobject);
}
else if (object.declaration().is(IfcSchema::IfcResource::Class()))
{
ntask->add_child("Resource", nobject);
}
else if (object.declaration().is(IfcSchema::IfcControl::Class()))
{
ntask->add_child("Control", nobject);
}
else
{
nobject.put("<xmlattr>.Type", object.declaration().name());
ntask->add_child("OperatesOn", nobject);
}
}
}
#endif
IfcSchema::IfcRelAssigns::list::ptr assignments = task->HasAssignments();
for (IfcSchema::IfcRelAssigns::list::it i = assignments->begin(); i != assignments->end(); ++i)
auto assignments = task.HasAssignments();
for (auto& assignment : assignments)
{
IfcSchema::IfcRelAssigns* assignment = *i;
if (assignment->declaration().is(IfcSchema::IfcRelAssignsToProduct::Class())) {
IfcSchema::IfcRelAssignsToProduct* assign_to_product = assignment->as<IfcSchema::IfcRelAssignsToProduct>();
IfcSchema::IfcProduct* product = assign_to_product->RelatingProduct()->as<IfcSchema::IfcProduct>();
if (auto assign_to_product = assignment.as<IfcSchema::IfcRelAssignsToProduct>()) {
IfcSchema::IfcRoot product = assign_to_product.RelatingProduct().as<IfcSchema::IfcProduct>();
if (!product) {
product = assign_to_product.RelatingProduct().as<IfcSchema::IfcTypeProduct>();
}
ptree nobject;
nobject.put("<xmlattr>.id", product->GlobalId());
nobject.put("<xmlattr>.id", product.GlobalId());
ntask->add_child("Output", nobject);
}
}
#ifdef SCHEMA_IfcObjectDefinition_HAS_IsNestedBy
IfcSchema::IfcRelNests::list::ptr nested_by = task->IsNestedBy();
for (IfcSchema::IfcRelNests::list::it it = nested_by->begin(); it != nested_by->end(); ++it)
auto nested_by = task.IsNestedBy();
for (auto& rel : nested_by)
{
IfcSchema::IfcObjectDefinition::list::ptr related_objects = (*it)->RelatedObjects();
for (IfcSchema::IfcObjectDefinition::list::it it2 = related_objects->begin(); it2 != related_objects->end(); ++it2)
auto related_objects = rel.RelatedObjects();
for (auto& object : related_objects)
{
if (!(*it2)->declaration().is(IfcSchema::IfcTask::Class())) {
continue;
}
IfcSchema::IfcTask* task2 = (*it2)->as<IfcSchema::IfcTask>();
format_tasks(mapping, task2, *ntask);
if (auto task2 = object.as<IfcSchema::IfcTask>()) {
format_tasks(mapping, task2, *ntask);
}
}
}
#endif
@@ -550,12 +543,12 @@ void format_tasks(ifcopenshell::geometry::abstract_mapping* mapping, IfcSchema::
void POSTFIX_SCHEMA(XmlSerializer)::finalize() {
POSTFIX_SCHEMA(argument_name_map).insert(std::make_pair("GlobalId", "id"));
IfcSchema::IfcProject::list::ptr projects = file->instances_by_type<IfcSchema::IfcProject>();
if (projects->size() != 1) {
auto projects = file->instances_by_type<IfcSchema::IfcProject>();
if (projects.size() != 1) {
Logger::Message(Logger::LOG_ERROR, "Expected a single IfcProject");
return;
}
IfcSchema::IfcProject* project = *projects->begin();
IfcSchema::IfcProject& project = projects.front();
ptree root, header, units, decomposition, properties, quantities, types, layers, materials, work, calendars, connections, groups;
@@ -570,20 +563,20 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() {
};
// Write the SPF header as XML nodes.
BOOST_FOREACH(const std::string & s, catch_exceptions([this]() { return file->header().file_description()->description(); })) {
BOOST_FOREACH(const std::string & s, catch_exceptions([this]() { return file->header().file_description().description(); })) {
header.add_child("file_description.description", ptree(s));
}
BOOST_FOREACH(const std::string& s, catch_exceptions([this]() { return file->header().file_name()->author(); })) {
BOOST_FOREACH(const std::string& s, catch_exceptions([this]() { return file->header().file_name().author(); })) {
header.add_child("file_name.author", ptree(s));
}
BOOST_FOREACH(const std::string& s, catch_exceptions([this]() { return file->header().file_name()->organization(); })) {
BOOST_FOREACH(const std::string& s, catch_exceptions([this]() { return file->header().file_name().organization(); })) {
header.add_child("file_name.organization", ptree(s));
}
BOOST_FOREACH(const std::string& s, catch_exceptions([this]() { return file->header().file_schema()->schema_identifiers(); })) {
BOOST_FOREACH(const std::string& s, catch_exceptions([this]() { return file->header().file_schema().schema_identifiers(); })) {
header.add_child("file_schema.schema_identifiers", ptree(s));
}
try {
header.put("file_description.implementation_level", file->header().file_description()->implementation_level());
header.put("file_description.implementation_level", file->header().file_description().implementation_level());
}
catch (const IfcParse::IfcException& ex) {
std::stringstream ss;
@@ -591,7 +584,7 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() {
Logger::Message(Logger::LOG_ERROR, ss.str());
}
try {
header.put("file_name.name", file->header().file_name()->name());
header.put("file_name.name", file->header().file_name().name());
}
catch (const IfcParse::IfcException& ex) {
std::stringstream ss;
@@ -599,7 +592,7 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() {
Logger::Message(Logger::LOG_ERROR, ss.str());
}
try {
header.put("file_name.time_stamp", file->header().file_name()->time_stamp());
header.put("file_name.time_stamp", file->header().file_name().time_stamp());
}
catch (const IfcParse::IfcException& ex) {
std::stringstream ss;
@@ -607,7 +600,7 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() {
Logger::Message(Logger::LOG_ERROR, ss.str());
}
try {
header.put("file_name.preprocessor_version", file->header().file_name()->preprocessor_version());
header.put("file_name.preprocessor_version", file->header().file_name().preprocessor_version());
}
catch (const IfcParse::IfcException& ex) {
std::stringstream ss;
@@ -615,7 +608,7 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() {
Logger::Message(Logger::LOG_ERROR, ss.str());
}
try {
header.put("file_name.originating_system", file->header().file_name()->originating_system());
header.put("file_name.originating_system", file->header().file_name().originating_system());
}
catch (const IfcParse::IfcException& ex) {
std::stringstream ss;
@@ -624,7 +617,7 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() {
}
try {
// @nb inconsistent spelling
header.put("file_name.authorization", file->header().file_name()->authorization());
header.put("file_name.authorization", file->header().file_name().authorization());
}
catch (const IfcParse::IfcException& ex) {
std::stringstream ss;
@@ -636,20 +629,19 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() {
descend(mapping_, project, decomposition);
// Write all property sets and values as XML nodes.
IfcSchema::IfcPropertySet::list::ptr psets = file->instances_by_type<IfcSchema::IfcPropertySet>();
for (IfcSchema::IfcPropertySet::list::it it = psets->begin(); it != psets->end(); ++it) {
IfcSchema::IfcPropertySet* pset = *it;
auto psets = file->instances_by_type<IfcSchema::IfcPropertySet>();
for (auto& pset : psets) {
ptree* node = format_entity_instance(mapping_, pset, properties);
if (node) {
format_properties(mapping_, pset->HasProperties(), *node);
format_properties(mapping_, pset.HasProperties(), *node);
}
}
// Write all group sets and values as XML nodes.
IfcSchema::IfcGroup::list::ptr gsets = file->instances_by_type<IfcSchema::IfcGroup>();
auto gsets = file->instances_by_type<IfcSchema::IfcGroup>();
std::set<std::string> notRootGroups; //selfname, fathername
for (IfcSchema::IfcGroup::list::it it = gsets->begin(); it != gsets->end(); ++it) {
writeGroupToNode(mapping_, *it, groups, notRootGroups);
for (auto& g : gsets) {
writeGroupToNode(mapping_, g, groups, notRootGroups);
}
for (auto it = groups.begin(); it != groups.end();) {
if (notRootGroups.find(it->second.get<std::string>("<xmlattr>.Name")) != notRootGroups.end()) {
@@ -660,33 +652,27 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() {
}
// Write all quantities and values as XML nodes.
IfcSchema::IfcElementQuantity::list::ptr qtosets = file->instances_by_type<IfcSchema::IfcElementQuantity>();
for (IfcSchema::IfcElementQuantity::list::it it = qtosets->begin(); it != qtosets->end(); ++it) {
IfcSchema::IfcElementQuantity* qto = *it;
auto qtosets = file->instances_by_type<IfcSchema::IfcElementQuantity>();
for (auto& qto : qtosets) {
ptree* node = format_entity_instance(mapping_, qto, quantities);
if (node) {
format_quantities(mapping_, qto->Quantities(), *node);
format_quantities(mapping_, qto.Quantities(), *node);
}
}
// Write all work schedules and values as XML nodes.
ptree pwork_schedules;
IfcSchema::IfcWorkSchedule::list::ptr pschedules = file->instances_by_type<IfcSchema::IfcWorkSchedule>();
for (IfcSchema::IfcWorkSchedule::list::it it = pschedules->begin(); it != pschedules->end(); ++it) {
IfcSchema::IfcWorkSchedule* schedule = *it;
auto pschedules = file->instances_by_type<IfcSchema::IfcWorkSchedule>();
for (auto& schedule : pschedules) {
ptree* nschedule = format_entity_instance(mapping_, schedule, pwork_schedules);
if(nschedule) {
IfcSchema::IfcRelAssignsToControl::list::ptr controls = schedule->Controls();
for(IfcSchema::IfcRelAssignsToControl::list::it it2 = controls->begin(); it2 != controls->end(); ++it2) {
IfcSchema::IfcRelAssignsToControl* control = *it2;
IfcSchema::IfcObjectDefinition::list::ptr objects = control->RelatedObjects();
for(IfcSchema::IfcObjectDefinition::list::it it3 = objects->begin(); it3 != objects->end(); ++it3) {
IfcSchema::IfcObjectDefinition* object = *it3;
if (object && object->declaration().is(IfcSchema::IfcTask::Class())) {
IfcSchema::IfcTask* task = object->as<IfcSchema::IfcTask>();
auto controls = schedule.Controls();
for(auto& control : controls) {
auto objects = control.RelatedObjects();
for(auto& object : objects) {
if (object && object.declaration().is(IfcSchema::IfcTask::Class())) {
IfcSchema::IfcTask task = object.as<IfcSchema::IfcTask>();
format_tasks(mapping_, task, *nschedule);
}
}
@@ -697,22 +683,20 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() {
// Write all work plans and values as XML nodes.
ptree pwork_plans;
IfcSchema::IfcWorkPlan::list::ptr pplans = file->instances_by_type<IfcSchema::IfcWorkPlan>();
for (IfcSchema::IfcWorkPlan::list::it it = pplans->begin(); it != pplans->end(); ++it) {
IfcSchema::IfcWorkPlan* plan = *it;
auto pplans = file->instances_by_type<IfcSchema::IfcWorkPlan>();
for (auto& plan : pplans) {
ptree* nschedule = format_entity_instance(mapping_, plan, pwork_plans);
if (nschedule) {
#ifdef SCHEMA_IfcObjectDefinition_HAS_IsDecomposedBy
auto decomposed_by = plan->IsDecomposedBy();
for (auto it2 = decomposed_by->begin(); it2 != decomposed_by->end(); ++it2)
auto decomposed_by = plan.IsDecomposedBy();
for (auto& rel : decomposed_by)
{
IfcSchema::IfcObjectDefinition::list::ptr related_objects = (*it2)->RelatedObjects();
for (IfcSchema::IfcObjectDefinition::list::it it3 = related_objects->begin(); it3 != related_objects->end(); ++it3)
auto related_objects = rel.RelatedObjects();
for (auto& work_schedule : related_objects)
{
IfcSchema::IfcObjectDefinition* work_schedule = *it3;
ptree pwork_schedule;
pwork_schedule.put("<xmlattr>.id", work_schedule->GlobalId());
pwork_schedule.put("<xmlattr>.id", work_schedule.GlobalId());
nschedule->add_child("IfcWorkSchedule", pwork_schedule);
}
}
@@ -723,51 +707,43 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() {
// Write all work calendars and values as XML nodes.
#ifdef SCHEMA_HAS_IfcWorkCalendar
IfcSchema::IfcWorkCalendar::list::ptr pcalendars = file->instances_by_type<IfcSchema::IfcWorkCalendar>();
for (IfcSchema::IfcWorkCalendar::list::it it = pcalendars->begin(); it != pcalendars->end(); ++it) {
IfcSchema::IfcWorkCalendar* calendar = *it;
auto pcalendars = file->instances_by_type<IfcSchema::IfcWorkCalendar>();
for (auto& calendar : pcalendars) {
ptree* ncalendar = format_entity_instance(mapping_, calendar, calendars);
if (ncalendar) {
IfcSchema::IfcWorkTime::list::ptr working_times = calendar->WorkingTimes().value_or(nullptr);
if (working_times != nullptr) {
for (IfcSchema::IfcWorkTime::list::it it2 = working_times->begin(); it2 != working_times->end(); ++it2)
{
IfcSchema::IfcWorkTime* working_time = *it2;
format_entity_instance(mapping_, working_time, *ncalendar);
}
auto working_times = calendar.WorkingTimes().value_or(std::vector<IfcSchema::IfcWorkTime>{});
for (auto& working_time : working_times)
{
format_entity_instance(mapping_, working_time, *ncalendar);
}
}
}
#endif
IfcSchema::IfcRelConnectsElements::list::ptr pconnections = file->instances_by_type<IfcSchema::IfcRelConnectsElements>();
for (IfcSchema::IfcRelConnectsElements::list::it it = pconnections->begin(); it != pconnections->end(); ++it) {
IfcSchema::IfcRelConnectsElements* connection = *it;
auto pconnections = file->instances_by_type<IfcSchema::IfcRelConnectsElements>();
for (auto& connection : pconnections) {
ptree* nconnection = format_entity_instance(mapping_, connection, connections);
ptree nrelatedElement;
ptree nrelatingElement;
format_entity_instance(mapping_,connection->RelatedElement(), nrelatedElement, true);
format_entity_instance(mapping_,connection->RelatingElement(), nrelatingElement, true);
format_entity_instance(mapping_,connection.RelatedElement(), nrelatedElement, true);
format_entity_instance(mapping_,connection.RelatingElement(), nrelatingElement, true);
nconnection->add_child("RelatedElement", nrelatedElement);
nconnection->add_child("RelatingElement", nrelatingElement);
}
// Write all type objects as XML nodes.
IfcSchema::IfcTypeObject::list::ptr type_objects = file->instances_by_type<IfcSchema::IfcTypeObject>();
for (IfcSchema::IfcTypeObject::list::it it = type_objects->begin(); it != type_objects->end(); ++it) {
IfcSchema::IfcTypeObject* type_object = *it;
auto type_objects = file->instances_by_type<IfcSchema::IfcTypeObject>();
for (auto& type_object : type_objects) {
ptree* node = descend(mapping_, type_object, types);
if (node && type_object->HasPropertySets()) {
IfcSchema::IfcPropertySetDefinition::list::ptr property_sets = *type_object->HasPropertySets();
for (IfcSchema::IfcPropertySetDefinition::list::it jt = property_sets->begin(); jt != property_sets->end(); ++jt) {
IfcSchema::IfcPropertySetDefinition* pset = *jt;
if (pset->declaration().is(IfcSchema::IfcPropertySet::Class())) {
if (node && type_object.HasPropertySets()) {
auto property_sets = *type_object.HasPropertySets();
for (auto& pset : property_sets) {
if (pset.declaration().is(IfcSchema::IfcPropertySet::Class())) {
format_entity_instance(mapping_, pset, *node, true);
}
}
@@ -775,16 +751,15 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() {
}
// Write all assigned units as XML nodes.
auto unit_assignments = project->UnitsInContext()->Units();
for (auto it = unit_assignments->begin(); it != unit_assignments->end(); ++it) {
if ((*it)->declaration().is(IfcSchema::IfcNamedUnit::Class())) {
IfcSchema::IfcNamedUnit* named_unit = (*it)->as<IfcSchema::IfcNamedUnit>();
auto unit_assignments = project.UnitsInContext().Units();
for (auto& unit : unit_assignments) {
if (auto named_unit = unit.as<IfcSchema::IfcNamedUnit>()) {
ptree* node = format_entity_instance(mapping_, named_unit, units);
if (node) {
node->put("<xmlattr>.SI_equivalent", IfcParse::get_SI_equivalent<IfcSchema>(named_unit));
}
} else if ((*it)->declaration().is(IfcSchema::IfcMonetaryUnit::Class())) {
format_entity_instance(mapping_, (*it)->as<IfcSchema::IfcMonetaryUnit>(), units);
} else if (auto mon_unit = unit.as<IfcSchema::IfcMonetaryUnit>()) {
format_entity_instance(mapping_, mon_unit, units);
}
}
@@ -792,49 +767,50 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() {
// so use names as the IDs and only insert those with unique names. In case of possible duplicate names/IDs
// the first IfcPresentationLayerAssignment occurrence takes precedence.
std::set<std::string> layer_names;
IfcSchema::IfcPresentationLayerAssignment::list::ptr layer_assignments = file->instances_by_type<IfcSchema::IfcPresentationLayerAssignment>();
for (IfcSchema::IfcPresentationLayerAssignment::list::it it = layer_assignments->begin(); it != layer_assignments->end(); ++it) {
const std::string& name = (*it)->Name();
auto layer_assignments = file->instances_by_type<IfcSchema::IfcPresentationLayerAssignment>();
for (auto& assignment : layer_assignments) {
const std::string& name = assignment.Name();
if (layer_names.find(name) == layer_names.end()) {
layer_names.insert(name);
ptree node;
node.put("<xmlattr>.id", name);
format_entity_instance(mapping_, *it, node, layers);
format_entity_instance(mapping_, assignment, node, layers);
}
}
IfcSchema::IfcRelAssociatesMaterial::list::ptr materal_associations = file->instances_by_type<IfcSchema::IfcRelAssociatesMaterial>();
std::set<IfcSchema::IfcMaterialSelect*> emitted_materials;
for (IfcSchema::IfcRelAssociatesMaterial::list::it it = materal_associations->begin(); it != materal_associations->end(); ++it) {
IfcSchema::IfcMaterialSelect* mat = (**it).RelatingMaterial();
auto materal_associations = file->instances_by_type<IfcSchema::IfcRelAssociatesMaterial>();
std::set<express::Base> emitted_materials;
for (auto& rel : materal_associations) {
IfcSchema::IfcMaterialSelect mat = rel.RelatingMaterial();
if (emitted_materials.find(mat) == emitted_materials.end()) {
emitted_materials.insert(mat);
ptree node;
node.put("<xmlattr>.id", qualify_unrooted_instance(mat));
if (mat->as<IfcSchema::IfcMaterialLayerSetUsage>() || mat->as<IfcSchema::IfcMaterialLayerSet>()) {
IfcSchema::IfcMaterialLayerSet* layerset = mat->as<IfcSchema::IfcMaterialLayerSet>();
// @todo this does not handle IfcMaterialProfileSetUsage and IfcMaterialConstituentSet
if (mat.concrete().as<IfcSchema::IfcMaterialUsageDefinition>() || mat.concrete().as<IfcSchema::IfcMaterialLayerSet>()) {
IfcSchema::IfcMaterialLayerSet layerset = mat.concrete().as<IfcSchema::IfcMaterialLayerSet>();
if (!layerset) {
layerset = mat->as<IfcSchema::IfcMaterialLayerSetUsage>()->ForLayerSet();
layerset = mat.concrete().as<IfcSchema::IfcMaterialLayerSetUsage>().ForLayerSet();
}
if (layerset->LayerSetName()) {
node.put("<xmlattr>.LayerSetName", *layerset->LayerSetName());
if (layerset.LayerSetName()) {
node.put("<xmlattr>.LayerSetName", *layerset.LayerSetName());
}
IfcSchema::IfcMaterialLayer::list::ptr ls = layerset->MaterialLayers();
for (IfcSchema::IfcMaterialLayer::list::it jt = ls->begin(); jt != ls->end(); ++jt) {
auto ls = layerset.MaterialLayers();
for (auto& layer : ls) {
ptree subnode;
if ((*jt)->Material()) {
subnode.put("<xmlattr>.Name", (*jt)->Material()->Name());
if (layer.Material()) {
subnode.put("<xmlattr>.Name", layer.Material());
}
format_entity_instance(mapping_, *jt, subnode, node);
format_entity_instance(mapping_, layer, subnode, node);
}
} else if (mat->as<IfcSchema::IfcMaterialList>()) {
IfcSchema::IfcMaterial::list::ptr mats = mat->as<IfcSchema::IfcMaterialList>()->Materials();
for (IfcSchema::IfcMaterial::list::it jt = mats->begin(); jt != mats->end(); ++jt) {
} else if (auto matlist = mat.concrete().as<IfcSchema::IfcMaterialList>()) {
auto mats = matlist.Materials();
for (auto& mat : mats) {
ptree subnode;
format_entity_instance(mapping_, *jt, subnode, node);
format_entity_instance(mapping_, mat, subnode, node);
}
}
format_entity_instance(mapping_, mat->as<IfcUtil::IfcBaseEntity>(), node, materials);
format_entity_instance(mapping_, mat.concrete(), node, materials);
}
}