diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 359795478b..ce8ea5013e 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -104,6 +104,7 @@ int main(int argc, char** argv) { std::string bounds; uint32_t hdf5_chunk_size; std::vector entity_vector; + std::vector hdf5_ref_attributes; boost::program_options::options_description geom_options; geom_options.add_options() ("plan", @@ -155,6 +156,8 @@ int main(int argc, char** argv) { ("hdf5-instantiate-inverse", "") ("hdf5-instantiate-select", "") ("hdf5-chunk-size", boost::program_options::value(&hdf5_chunk_size), "") + ("hdf5-ref-attributes", boost::program_options::value< std::vector >(&hdf5_ref_attributes)->multitoken(), + "") ("include", "Specifies that the entities listed after --entities are to be included") ("exclude", @@ -284,6 +287,8 @@ int main(int argc, char** argv) { settings.fix_global_id() = vmap.count("hdf5-fix-global-id") != 0; settings.instantiate_inverse() = vmap.count("hdf5-instantiate-inverse") != 0; settings.instantiate_select() = vmap.count("hdf5-instantiate-select") != 0; + std::sort(hdf5_ref_attributes.begin(), hdf5_ref_attributes.end()); + settings.ref_attributes() = hdf5_ref_attributes; if (vmap.count("hdf5-chunk-size") == 1) { settings.chunk_size() = hdf5_chunk_size; } diff --git a/src/ifcgeom/IfcGeomIterator.h b/src/ifcgeom/IfcGeomIterator.h index 9913b1e876..87b298c6fa 100644 --- a/src/ifcgeom/IfcGeomIterator.h +++ b/src/ifcgeom/IfcGeomIterator.h @@ -398,7 +398,7 @@ namespace IfcGeom { try { const IfcUtil::IfcBaseClass* ifc_entity = ifc_file->entityById(id); - instance_type = IfcSchema::Type::ToString(ifc_entity->type()); + instance_type = IfcSchema::Type::ToString(ifc_entity->declaration().type()); if ( ifc_entity->declaration().is(IfcSchema::Type::IfcProduct) ) { IfcSchema::IfcProduct* ifc_product = (IfcSchema::IfcProduct*)ifc_entity; diff --git a/src/ifcparse/Hdf5Settings.h b/src/ifcparse/Hdf5Settings.h index c8a0ae2789..431bae7b3d 100644 --- a/src/ifcparse/Hdf5Settings.h +++ b/src/ifcparse/Hdf5Settings.h @@ -20,12 +20,16 @@ #ifndef HDF5SETTINGS_H #define HDF5SETTINGS_H +#include +#include + namespace IfcParse { struct Hdf5Settings { private: bool compress_, fix_cartesian_point_, fix_global_id_, instantiate_select_, instantiate_inverse_; unsigned int chunk_size_; + std::vector ref_attributes_; public: Hdf5Settings() : compress_(false) @@ -41,15 +45,18 @@ namespace IfcParse { bool fix_global_id() const { return fix_global_id_; } bool instantiate_select() const { return instantiate_select_; } bool instantiate_inverse() const { return instantiate_inverse_; } - + bool& compress() { return compress_; } bool& fix_cartesian_point() { return fix_cartesian_point_; } bool& fix_global_id() { return fix_global_id_; } bool& instantiate_select() { return instantiate_select_; } bool& instantiate_inverse() { return instantiate_inverse_; } - + unsigned int chunk_size() const { return chunk_size_; } unsigned int& chunk_size() { return chunk_size_; } + + const std::vector& ref_attributes() const { return ref_attributes_; } + std::vector& ref_attributes() { return ref_attributes_; } }; } diff --git a/src/ifcparse/IfcHdf5File.cpp b/src/ifcparse/IfcHdf5File.cpp index 51a2de4043..518105644d 100644 --- a/src/ifcparse/IfcHdf5File.cpp +++ b/src/ifcparse/IfcHdf5File.cpp @@ -1,3 +1,7 @@ +#include + +#include + #include "IfcHdf5File.h" #include "H5pubconf.h" @@ -124,8 +128,13 @@ H5::CompType* IfcParse::IfcHdf5File::map_entity(const IfcParse::entity* e) { const std::string& name = (*it)->name(); const bool is_optional = (*it)->optional(); const H5::DataType* type; - if (overridden_types.find(name) != overridden_types.end()) { - type = overridden_types.find(name)->second; + const std::string qualified_attr_name = e->name() + "." + name; + if (std::binary_search(settings_.ref_attributes().begin(), settings_.ref_attributes().end(), qualified_attr_name)) { + type = new H5::PredType(H5::PredType::STD_REF_OBJ); + } else if (overridden_types.find(qualified_attr_name) != overridden_types.end()) { + type = overridden_types.find(qualified_attr_name)->second; + } else if (overridden_types.find("*." + name) != overridden_types.end()) { + type = overridden_types.find("*." + name)->second; } else { type = map_type((*it)->type_of_attribute()); } @@ -190,12 +199,12 @@ void IfcParse::IfcHdf5File::init_default_types() { default_cpp_type_names[IfcUtil::Argument_INT] = "integer"; if (settings_.fix_global_id()) { - overridden_types["GlobalId"] = new H5::StrType(H5::PredType::C_S1, 22); + overridden_types["*.GlobalId"] = new H5::StrType(H5::PredType::C_S1, 22); } if (settings_.fix_cartesian_point()) { hsize_t dims = 3; - overridden_types["Coordinates"] = new H5::ArrayType(*default_types[simple_type::real_type], 1, &dims); - overridden_types["DirectionRatios"] = new H5::ArrayType(*default_types[simple_type::real_type], 1, &dims); + overridden_types["IfcCartesianPoint.Coordinates"] = new H5::ArrayType(*default_types[simple_type::real_type], 1, &dims); + overridden_types["IfcDirection.DirectionRatios"] = new H5::ArrayType(*default_types[simple_type::real_type], 1, &dims); } } @@ -412,6 +421,244 @@ void IfcParse::IfcHdf5File::write_aggregate(void*& ptr, const IfcEntityList::ptr write_vlen_t(ptr, n_elements, aggr_data); } +template +void IfcParse::IfcHdf5File::write_aggregate2(void*& ptr, const std::vector< std::vector >& ts) const { + size_t elem_size = sizeof(hvl_t); + size_t n_elements = ts.size(); + size_t size_in_bytes = elem_size * n_elements; + void* aggr_data = allocator.allocate(size_in_bytes); + void* aggr_ptr = aggr_data; + for (std::vector< std::vector >::const_iterator it = ts.begin(); it != ts.end(); ++it) { + write_aggregate(aggr_ptr, *it); + } + write_vlen_t(ptr, n_elements, aggr_data); +} + +template +void IfcParse::IfcHdf5File::write_reference_attribute(void*& ptr, const std::string& dsn, const std::vector& vs) { + const std::string dsn_path = "/population/" + dsn; + const hsize_t s = vs.size(); + const H5::DataType& dt = *get_datatype(); + const size_t size_in_bytes = dt.getSize() * vs.size(); + + H5::DataSpace space(1, &s); + + void* buffer = allocator.allocate(size_in_bytes); + void* ds_ptr = buffer; + for (auto it = vs.begin(); it != vs.end(); ++it) { + write_number_of_size(ds_ptr, dt.getSize(), *it); + } + + // TODO: Refactor + hsize_t chunk; + if (settings_.chunk_size() > 0 && settings_.chunk_size() < s) { + chunk = static_cast(settings_.chunk_size()); + } else { + chunk = s; + } + + const H5::DSetCreatPropList* plist; + // H5O_MESG_MAX_SIZE = 65536 + const bool compact = size_in_bytes < (1 << 15); + if (settings_.compress() && !compact) { + H5::DSetCreatPropList* plist_ = new H5::DSetCreatPropList; + plist_->setChunk(1, &chunk); + // D'oh. Order is significant, according to h5ex_d_shuffle.c + plist_->setShuffle(); + plist_->setDeflate(9); + plist = plist_; + } else if (compact) { + H5::DSetCreatPropList* plist_ = new H5::DSetCreatPropList; + // Set compact according to h5ex_d_compact.c + plist_->setLayout(H5D_COMPACT); + plist = plist_; + } else if (chunk != s){ + H5::DSetCreatPropList* plist_ = new H5::DSetCreatPropList; + plist_->setChunk(1, &chunk); + plist = plist_; + } else { + plist = &H5::DSetCreatPropList::DEFAULT; + } + + H5::DataSet ds = population_group.createDataSet(dsn, dt, space, *plist); + ds.write(buffer, dt); + space.close(); + + ds.reference(ptr, dsn_path.c_str()); + advance(ptr, sizeof(hobj_ref_t)); + + if (plist != &H5::DSetCreatPropList::DEFAULT) { + // ->close() doesn't work due to const, hack hack hack + H5Pclose(plist->getId()); + } + + delete[] buffer; + ds.close(); +} + +template +void IfcParse::IfcHdf5File::write_reference_attribute2(void*& ptr, const std::string& dsn, const std::vector< std::vector >& vs) { + + // See if the attribute is a 'jagged' array in which case a single row of + // vlens is written. Otherwise a two dimensional dataset is created. + bool is_rectangular = true; + size_t w = 0; + for (auto it = vs.begin(); it != vs.end(); ++it) { + if (it == vs.begin()) { + w = it->size(); + } else { + if (w != it->size()) { + is_rectangular = false; + break; + } + } + } + + // TODO: Please use smart pointers next time + hsize_t* s; + hsize_t* chunk; + const H5::DataType* dt; + H5::DataType* dt2; + bool scaled_type = false; + + if (is_rectangular) { + s = new hsize_t[2]; + s[0] = vs.size(); + s[1] = w; + + // Try to find the narrowest integer that can represent values in the dataset + dt = dt2 = 0; + if (std::numeric_limits::is_integer) { + T min_value = std::numeric_limits::max(); + T max_value = std::numeric_limits::min(); + for (auto it = vs.begin(); it != vs.end(); ++it) { + for (auto jt = it->begin(); jt != it->end(); ++jt) { + if ((*jt) > max_value) { + max_value = *jt; + } + if ((*jt) < min_value) { + min_value = *jt; + } + } + } + + scaled_type = true; + if (min_value >= std::numeric_limits::min() && max_value <= std::numeric_limits::max()) { + dt = dt2 = new H5::PredType(H5::PredType::NATIVE_UINT8); + } else if (min_value >= std::numeric_limits::min() && max_value <= std::numeric_limits::max()) { + dt = dt2 = new H5::PredType(H5::PredType::NATIVE_INT8); + } else if (min_value >= std::numeric_limits::min() && max_value <= std::numeric_limits::max()) { + dt = dt2 = new H5::PredType(H5::PredType::NATIVE_UINT16); + } else if (min_value >= std::numeric_limits::min() && max_value <= std::numeric_limits::max()) { + dt = dt2 = new H5::PredType(H5::PredType::NATIVE_INT16); + } else if (min_value >= std::numeric_limits::min() && max_value <= std::numeric_limits::max()) { + dt = dt2 = new H5::PredType(H5::PredType::NATIVE_UINT32); + } else if (min_value >= std::numeric_limits::min() && max_value <= std::numeric_limits::max()) { + dt = dt2 = new H5::PredType(H5::PredType::NATIVE_INT32); + } else { + scaled_type = false; + } + + } + + if (dt == 0) { + dt = get_datatype(); + } + + } else { + s = new hsize_t(vs.size()); + dt = dt2 = new H5::VarLenType(get_datatype()); + } + + const std::string dsn_path = "/population/" + dsn; + const size_t size_in_bytes = is_rectangular + ? sizeof(T) * vs.size() * w + : sizeof(hvl_t) * vs.size(); + + // TODO: Refactor + const bool is_chunked = settings_.chunk_size() > 0 && settings_.chunk_size() < s[0]; + if (is_chunked) { + if (is_rectangular) { + chunk = new hsize_t[2]; + chunk[0] = settings_.chunk_size(); + chunk[1] = s[1]; + } else { + chunk = new hsize_t(vs.size()); + } + } else { + chunk = s; + } + + const H5::DSetCreatPropList* plist; + // H5O_MESG_MAX_SIZE = 65536 + const bool compact = size_in_bytes < (1 << 15); + if (settings_.compress() && !compact) { + H5::DSetCreatPropList* plist_ = new H5::DSetCreatPropList; + plist_->setChunk(is_rectangular ? 2 : 1, chunk); + // D'oh. Order is significant, according to h5ex_d_shuffle.c + plist_->setShuffle(); + plist_->setDeflate(9); + plist = plist_; + } else if (compact) { + H5::DSetCreatPropList* plist_ = new H5::DSetCreatPropList; + // Set compact according to h5ex_d_compact.c + plist_->setLayout(H5D_COMPACT); + plist = plist_; + } else if (chunk != s){ + H5::DSetCreatPropList* plist_ = new H5::DSetCreatPropList; + plist_->setChunk(is_rectangular ? 2 : 1, chunk); + plist = plist_; + } else { + plist = &H5::DSetCreatPropList::DEFAULT; + } + + H5::DataSpace space(is_rectangular ? 2 : 1, s); + H5::DataSet ds = population_group.createDataSet(dsn, *dt, space, *plist); + + void* buffer = allocator.allocate(size_in_bytes); + void* ds_ptr = buffer; + for (auto it = vs.begin(); it != vs.end(); ++it) { + if (is_rectangular) { + for (auto jt = it->begin(); jt != it->end(); ++jt) { + write_number_of_size(ds_ptr, dt->getSize(), *jt); + } + } else { + write_aggregate(ds_ptr, *it); + } + } + ds.write(buffer, *dt); + space.close(); + + ds.reference(ptr, dsn_path.c_str()); + advance(ptr, sizeof(hobj_ref_t)); + + delete[] buffer; + ds.close(); + + if (plist != &H5::DSetCreatPropList::DEFAULT) { + // ->close() doesn't work due to const, hack hack hack + H5Pclose(plist->getId()); + } + + if (is_rectangular) { + delete[] s; + if (is_chunked) { + delete[] chunk; + } + if (scaled_type) { + dt2->close(); + delete dt; + } + } else { + dt2->close(); + delete dt; + delete s; + if (is_chunked) { + delete chunk; + } + } +} + void IfcParse::IfcHdf5File::write_schema(const IfcParse::schema_definition& schema) { // From h5ex_g_compact.c @@ -641,7 +888,8 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { // if (*it != IfcSchema::Type::IfcUnitAssignment) continue; - std::cerr << IfcSchema::Type::ToString(*it) << std::endl; + const std::string current_entity_name = IfcSchema::Type::ToString(*it); + std::cerr << current_entity_name << std::endl; #ifdef SORT_ON_NAME std::vector es; @@ -777,11 +1025,42 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { } } else { set_unset_mask |= 1 << i; - if (settings_.fix_global_id() && attribute_name == "GlobalId") { + if (member_type.getClass() == H5T_REFERENCE) { + // Something that comes from the ref_attributes settings + const std::string dsn = current_entity_name + "." + attribute_name + "_" + boost::lexical_cast(dat.id()); + switch(attr_value.type()) { + case IfcUtil::Argument_AGGREGATE_OF_INT: { + std::vector vs = attr_value; + write_reference_attribute(ptr, dsn, vs); + break; } + case IfcUtil::Argument_AGGREGATE_OF_BOOL: { + std::vector vs = attr_value; + write_reference_attribute(ptr, dsn, vs); + break; } + case IfcUtil::Argument_AGGREGATE_OF_DOUBLE: { + std::vector vs = attr_value; + write_reference_attribute(ptr, dsn, vs); + break; } + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT: { + std::vector< std::vector > vs = attr_value; + write_reference_attribute2(ptr, dsn, vs); + break; } + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_BOOL: { + std::vector< std::vector > vs = attr_value; + write_reference_attribute2(ptr, dsn, vs); + break; } + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE: { + std::vector< std::vector > vs = attr_value; + write_reference_attribute2(ptr, dsn, vs); + break; } + default: + throw IfcException(dsn + " is not a supported aggregate"); + } + } if (settings_.fix_global_id() && attribute_name == "GlobalId") { std::string s = attr_value; memcpy(static_cast(ptr), s.c_str(), s.size()); advance(ptr, s.length()); - } else if (settings_.fix_cartesian_point() && (attribute_name == "Coordinates" || attribute_name == "DirectionRatios")) { + } else if (settings_.fix_cartesian_point() && ((attribute_name == "Coordinates" && current_entity_name == "IfcCartesianPoint") || (attribute_name == "DirectionRatios" && current_entity_name == "IfcDirection"))) { std::vector ds = attr_value; for (auto it = ds.begin(); it != ds.end(); ++it) { write_number_of_size(ptr, default_types[simple_type::real_type]->getSize(), *it); @@ -849,6 +1128,10 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { std::vector ds = attr_value; write_aggregate(ptr, ds); break; } + case IfcUtil::Argument_AGGREGATE_OF_BOOL: { + std::vector ds = attr_value; + write_aggregate(ptr, ds); + break; } case IfcUtil::Argument_AGGREGATE_OF_DOUBLE: { std::vector ds = attr_value; write_aggregate(ptr, ds); @@ -861,6 +1144,18 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { std::vector ss = attr_value; write_aggregate(ptr, ss); break; } + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT: { + std::vector< std::vector > ds = attr_value; + write_aggregate2(ptr, ds); + break; } + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_BOOL: { + std::vector< std::vector > ds = attr_value; + write_aggregate2(ptr, ds); + break; } + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE: { + std::vector< std::vector > ds = attr_value; + write_aggregate2(ptr, ds); + break; } default: // Can be an empty list in which case parser does not know type if (attr_value.size() > 0) { diff --git a/src/ifcparse/IfcHdf5File.h b/src/ifcparse/IfcHdf5File.h index 30e11f2b47..f52d7f11de 100644 --- a/src/ifcparse/IfcHdf5File.h +++ b/src/ifcparse/IfcHdf5File.h @@ -114,6 +114,16 @@ namespace IfcParse { template void write_aggregate(void*& ptr, const T& ts) const; + + template + void write_aggregate2(void*& ptr, const std::vector< std::vector >& ts) const; + + template + void write_reference_attribute(void*& ptr, const std::string& dsn, const std::vector& vs); + + template + void write_reference_attribute2(void*& ptr, const std::string& dsn, const std::vector< std::vector >& vs); + public: typedef std::pair compound_member;