mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Conversion back from hdf to spf, standard profile only ftm
This commit is contained in:
@@ -35,6 +35,7 @@
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "../ifcparse/Hdf5Settings.h"
|
||||
#include "../ifcparse/IfcHdf5File.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
@@ -72,6 +73,7 @@ void printUsage(const boost::program_options::options_description& generic_optio
|
||||
<< " .xml XML Property definitions and decomposition tree" << std::endl
|
||||
<< " .svg SVG Scalable Vector Graphics (2d floor plan)" << std::endl
|
||||
<< " .hdf HDF5 Efficient binary IFC serialization" << std::endl
|
||||
<< " .ifc IFC-SPF Standard p21 IFC serialization" << std::endl
|
||||
<< std::endl
|
||||
<< "Command line options" << std::endl << generic_options << std::endl
|
||||
<< "Advanced options" << std::endl << geom_options << std::endl;
|
||||
@@ -303,6 +305,28 @@ int main(int argc, char** argv) {
|
||||
write_log();
|
||||
// std::cin.get();
|
||||
return exit_code;
|
||||
} else if (output_extension == ".ifc") {
|
||||
bool success = false;
|
||||
const std::string input_extension = input_filename.substr(input_filename.size() - 4);
|
||||
if (input_extension == ".ifc") {
|
||||
IfcParse::IfcFile f;
|
||||
if (f.Init(input_filename)) {
|
||||
std::ofstream of(output_filename.c_str());
|
||||
of << f;
|
||||
success = true;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file");
|
||||
}
|
||||
} else if (input_extension == ".hdf") {
|
||||
std::ofstream fs(output_filename.c_str());
|
||||
IfcParse::IfcHdf5File::convert_to_spf(input_filename, fs);
|
||||
success = true;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unknown input extension");
|
||||
}
|
||||
|
||||
write_log();
|
||||
return success ? 0 : 1;
|
||||
}
|
||||
|
||||
IfcGeom::IteratorSettings settings;
|
||||
|
||||
+389
-30
@@ -1,5 +1,7 @@
|
||||
#include "../ifcparse/IfcHdf5File.h"
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
|
||||
#include <bitset>
|
||||
#include <limits>
|
||||
#include <H5pubconf.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
@@ -12,7 +14,8 @@ static boost::optional< std::vector<Argument*> > no_instances = boost::none;
|
||||
|
||||
class type_mapper {
|
||||
public:
|
||||
type_mapper(IfcParse::IfcFile& ifc_file, H5::H5File* hdf5_file, const IfcParse::Hdf5Settings& settings);
|
||||
type_mapper();
|
||||
type_mapper(IfcParse::IfcFile* ifc_file, H5::H5File* hdf5_file, const IfcParse::Hdf5Settings& settings);
|
||||
|
||||
H5::DataType* commit(H5::DataType* dt, const std::string& name);
|
||||
|
||||
@@ -30,7 +33,7 @@ private:
|
||||
bool padded_;
|
||||
bool referenced_;
|
||||
|
||||
IfcParse::IfcFile& ifc_file_;
|
||||
IfcParse::IfcFile* ifc_file_;
|
||||
H5::H5File* hdf5_file_;
|
||||
H5::Group schema_group_;
|
||||
H5::DataType* instance_reference_;
|
||||
@@ -140,7 +143,8 @@ void advance(void*& ptr, size_t n) {
|
||||
|
||||
template <typename T>
|
||||
void write(void*& ptr, const T& t) {
|
||||
*((T*)ptr) = t;
|
||||
// *((T*)ptr) = t;
|
||||
memcpy(ptr, &t, sizeof(T));
|
||||
advance(ptr, sizeof(T));
|
||||
}
|
||||
|
||||
@@ -416,7 +420,9 @@ public:
|
||||
break;
|
||||
case H5T_STRING:
|
||||
if (datatype_ == H5::StrType(H5::PredType::C_S1, H5T_VARIABLE)) {
|
||||
write(ptr, new char(0));
|
||||
// write(ptr, new char(0));
|
||||
memset(ptr, 0, sizeof(char*));
|
||||
advance(ptr, sizeof(char*));
|
||||
} else {
|
||||
write_string_of_size(ptr, datatype_.getSize(), "");
|
||||
}
|
||||
@@ -818,20 +824,53 @@ std::string type_mapper::flatten_aggregate_name(const IfcParse::parameter_type*
|
||||
}
|
||||
}
|
||||
|
||||
type_mapper::type_mapper(IfcParse::IfcFile& ifc_file, H5::H5File* hdf5_file, const IfcParse::Hdf5Settings& settings)
|
||||
type_mapper::type_mapper() {
|
||||
default_type_names_[IfcParse::simple_type::logical_type] = "logical";
|
||||
default_type_names_[IfcParse::simple_type::boolean_type] = "boolean";
|
||||
default_type_names_[IfcParse::simple_type::binary_type] = "binary";
|
||||
default_type_names_[IfcParse::simple_type::real_type] = "real";
|
||||
default_type_names_[IfcParse::simple_type::number_type] = "number";
|
||||
default_type_names_[IfcParse::simple_type::string_type] = "string";
|
||||
default_type_names_[IfcParse::simple_type::integer_type] = "integer";
|
||||
|
||||
default_cpp_type_names_[IfcUtil::Argument_BOOL] = "boolean";
|
||||
default_cpp_type_names_[IfcUtil::Argument_DOUBLE] = "real";
|
||||
default_cpp_type_names_[IfcUtil::Argument_STRING] = "string";
|
||||
default_cpp_type_names_[IfcUtil::Argument_INT] = "integer";
|
||||
}
|
||||
|
||||
type_mapper::type_mapper(IfcParse::IfcFile* ifc_file, H5::H5File* hdf5_file, const IfcParse::Hdf5Settings& settings)
|
||||
: ifc_file_(ifc_file)
|
||||
, hdf5_file_(hdf5_file)
|
||||
, settings_(settings)
|
||||
, padded_(settings_.profile() == IfcParse::Hdf5Settings::padded || settings_.profile() == IfcParse::Hdf5Settings::padded_referenced)
|
||||
, referenced_(settings_.profile() == IfcParse::Hdf5Settings::standard_referenced || settings_.profile() == IfcParse::Hdf5Settings::padded_referenced)
|
||||
{
|
||||
schema_group_ = hdf5_file_->openGroup(ifc_file_.schema()->name() + "_encoding");
|
||||
|
||||
default_types_.resize(IfcParse::simple_type::datatype_COUNT);
|
||||
default_type_names_.resize(IfcParse::simple_type::datatype_COUNT);
|
||||
default_cpp_type_names_.resize(IfcUtil::Argument_UNKNOWN);
|
||||
declared_types_.resize(IfcSchema::Type::UNDEFINED);
|
||||
|
||||
default_type_names_[IfcParse::simple_type::logical_type] = "logical";
|
||||
default_type_names_[IfcParse::simple_type::boolean_type] = "boolean";
|
||||
default_type_names_[IfcParse::simple_type::binary_type] = "binary";
|
||||
default_type_names_[IfcParse::simple_type::real_type] = "real";
|
||||
default_type_names_[IfcParse::simple_type::number_type] = "number";
|
||||
default_type_names_[IfcParse::simple_type::string_type] = "string";
|
||||
default_type_names_[IfcParse::simple_type::integer_type] = "integer";
|
||||
|
||||
default_cpp_type_names_[IfcUtil::Argument_BOOL] = "boolean";
|
||||
default_cpp_type_names_[IfcUtil::Argument_DOUBLE] = "real";
|
||||
default_cpp_type_names_[IfcUtil::Argument_STRING] = "string";
|
||||
default_cpp_type_names_[IfcUtil::Argument_INT] = "integer";
|
||||
|
||||
if (!ifc_file_ && !hdf5_file_) {
|
||||
// This mapper is only used to construct leaf names for select compounds
|
||||
return;
|
||||
}
|
||||
|
||||
schema_group_ = hdf5_file_->openGroup(ifc_file_->schema()->name() + "_encoding");
|
||||
|
||||
default_types_.resize(IfcParse::simple_type::datatype_COUNT);
|
||||
declared_types_.resize(IfcSchema::Type::UNDEFINED);
|
||||
|
||||
if (referenced_) {
|
||||
instance_reference_ = commit(new H5::PredType(H5::PredType::STD_REF_DSETREG), "_HDF_INSTANCE_REFERENCE_HANDLE_");
|
||||
@@ -862,19 +901,6 @@ type_mapper::type_mapper(IfcParse::IfcFile& ifc_file, H5::H5File* hdf5_file, con
|
||||
default_types_[IfcParse::simple_type::number_type] = &H5::PredType::NATIVE_DOUBLE;
|
||||
default_types_[IfcParse::simple_type::string_type] = new H5::StrType(H5::PredType::C_S1, H5T_VARIABLE);
|
||||
default_types_[IfcParse::simple_type::integer_type] = &H5::PredType::NATIVE_INT;
|
||||
|
||||
default_type_names_[IfcParse::simple_type::logical_type] = "logical";
|
||||
default_type_names_[IfcParse::simple_type::boolean_type] = "boolean";
|
||||
default_type_names_[IfcParse::simple_type::binary_type] = "binary";
|
||||
default_type_names_[IfcParse::simple_type::real_type] = "real";
|
||||
default_type_names_[IfcParse::simple_type::number_type] = "number";
|
||||
default_type_names_[IfcParse::simple_type::string_type] = "string";
|
||||
default_type_names_[IfcParse::simple_type::integer_type] = "integer";
|
||||
|
||||
default_cpp_type_names_[IfcUtil::Argument_BOOL] = "boolean";
|
||||
default_cpp_type_names_[IfcUtil::Argument_DOUBLE] = "real";
|
||||
default_cpp_type_names_[IfcUtil::Argument_STRING] = "string";
|
||||
default_cpp_type_names_[IfcUtil::Argument_INT] = "integer";
|
||||
}
|
||||
|
||||
H5::DataType* type_mapper::commit(H5::DataType* dt, const std::string& name) {
|
||||
@@ -1067,6 +1093,8 @@ std::pair<std::string, const H5::DataType*> type_mapper::make_select_leaf(const
|
||||
std::string name;
|
||||
const H5::DataType* dt = 0;
|
||||
|
||||
const bool should_return_type = ifc_file_ != nullptr && hdf5_file_ != nullptr;
|
||||
|
||||
if (decl) {
|
||||
while (decl->as_type_declaration()) {
|
||||
const IfcParse::parameter_type* leaf_pt = decl->as_type_declaration()->declared_type();
|
||||
@@ -1100,21 +1128,21 @@ std::pair<std::string, const H5::DataType*> type_mapper::make_select_leaf(const
|
||||
std::vector< IfcParse::IfcHdf5File::compound_member > members;
|
||||
members.push_back(std::make_pair(std::string("length"), new H5::PredType(H5::PredType::NATIVE_UINT32)));
|
||||
members.push_back(std::make_pair(std::string("data"), new H5::StrType(H5::PredType::C_S1, (size_t)visitor.max_length()[0] + 1)));
|
||||
dt = create_compound(members);
|
||||
if (should_return_type) dt = create_compound(members);
|
||||
|
||||
} else {
|
||||
dt = default_types_[st->declared_type()];
|
||||
if (should_return_type) dt = default_types_[st->declared_type()];
|
||||
}
|
||||
break;
|
||||
} else if (at) {
|
||||
name = flatten_aggregate_name(at);
|
||||
dt = (*this)(at);
|
||||
if (should_return_type) dt = (*this)(at);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!dt) {
|
||||
if (!dt && should_return_type) {
|
||||
if (decl->as_entity()) {
|
||||
name = "instance";
|
||||
dt = instance_reference_;
|
||||
@@ -1249,7 +1277,7 @@ public:
|
||||
H5::CompType* type_mapper::operator()(const IfcParse::entity* e, const boost::optional< std::vector<Argument*> >&, int, const hsize_t*) {
|
||||
|
||||
// List of entity instances of this type, no subtypes
|
||||
IfcEntityList::ptr incl_subtypes = ifc_file_.entitiesByType(e->name());
|
||||
IfcEntityList::ptr incl_subtypes = ifc_file_->entitiesByType(e->name());
|
||||
IfcEntityList::ptr instances(new IfcEntityList);
|
||||
if (incl_subtypes) {
|
||||
for (auto it = incl_subtypes->begin(); it != incl_subtypes->end(); ++it) {
|
||||
@@ -1399,7 +1427,7 @@ H5::EnumType* type_mapper::operator()(const IfcParse::enumeration_type* en, cons
|
||||
}
|
||||
|
||||
void type_mapper::operator()() {
|
||||
const IfcParse::schema_definition& schema = *ifc_file_.schema();
|
||||
const IfcParse::schema_definition& schema = *ifc_file_->schema();
|
||||
|
||||
for (auto it = schema.enumeration_types().begin(); it != schema.enumeration_types().end(); ++it) {
|
||||
declared_types_[(*it)->type()] = commit((*this)(*it), (*it)->name());
|
||||
@@ -1891,7 +1919,7 @@ void IfcParse::IfcHdf5File::write_schema(const IfcParse::schema_definition& sche
|
||||
|
||||
// init_default_types();
|
||||
|
||||
mapper_ = new type_mapper(ifc_file, file, settings_);
|
||||
mapper_ = new type_mapper(&ifc_file, file, settings_);
|
||||
(*(type_mapper*)mapper_)();
|
||||
};
|
||||
|
||||
@@ -2677,4 +2705,335 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) {
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
bool is_instance_ref(H5::DataType* dt) {
|
||||
if (dt->getClass() != H5T_COMPOUND) return false;
|
||||
H5::CompType* ct = (H5::CompType*) dt;
|
||||
return ct->getMemberName(0) == "_HDF5_dataset_index_";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T read_(void* buffer, H5::DataType* dt) {
|
||||
(void*)dt;
|
||||
T t;
|
||||
memcpy(&t, buffer, sizeof(T));
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T read(void* buffer, H5::DataType* dt) {
|
||||
return read_<T>(buffer, dt);
|
||||
}
|
||||
|
||||
template <>
|
||||
int read(void* buffer, H5::DataType* dt) {
|
||||
// TODO: Check for overflow
|
||||
// TODO: Check signed
|
||||
int i;
|
||||
switch (dt->getSize()) {
|
||||
case 1: i = (int) read_<int_of_size<1>::type>(buffer, dt); break;
|
||||
case 2: i = (int) read_<int_of_size<2>::type>(buffer, dt); break;
|
||||
case 4: i = (int) read_<int_of_size<4>::type>(buffer, dt); break;
|
||||
case 8: i = (int) read_<int_of_size<8>::type>(buffer, dt); break;
|
||||
default: throw std::runtime_error("Unexpected integer width");
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
template <>
|
||||
double read(void* buffer, H5::DataType* dt) {
|
||||
double d;
|
||||
switch (dt->getSize()) {
|
||||
case 4: d = read_<float_of_size<4>::type>(buffer, dt); break;
|
||||
case 8: d = read_<float_of_size<8>::type>(buffer, dt); break;
|
||||
default: throw std::runtime_error("Unexpected float width");
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
static const std::bitset<64> many_trues(std::numeric_limits<unsigned long>::max());
|
||||
static const std::string no_name = "NO_NAME";
|
||||
|
||||
class instance_resolver {
|
||||
private:
|
||||
H5::H5File& file_;
|
||||
std::vector<std::string> dataset_names_;
|
||||
|
||||
public:
|
||||
instance_resolver(H5::H5File& file)
|
||||
: file_(file)
|
||||
{
|
||||
H5::Group schema_group = file_.openGroup("IFC2X3_encoding");
|
||||
H5::Attribute names = schema_group.openAttribute("iso_10303_26_data_set_names");
|
||||
H5::DataType datatype = names.getDataType();
|
||||
if (datatype.getClass() != H5T_STRING || H5Tis_variable_str(datatype.getId()) <= 0) {
|
||||
throw std::runtime_error("Expected variable string attribute");
|
||||
}
|
||||
|
||||
H5::DataSpace dataspace = names.getSpace();
|
||||
if (dataspace.getSimpleExtentNdims() != 1) {
|
||||
throw std::runtime_error("Expected one-dimensional attribute");
|
||||
}
|
||||
|
||||
hsize_t dim;
|
||||
dataspace.getSimpleExtentDims(&dim, NULL);
|
||||
dataset_names_.reserve(dim);
|
||||
|
||||
void* buffer;
|
||||
uint8_t* ptr;
|
||||
buffer = ptr = new uint8_t[datatype.getSize() * (size_t) dim];
|
||||
names.read(datatype, buffer);
|
||||
|
||||
while (dim--) {
|
||||
dataset_names_.push_back(*(char**) ptr);
|
||||
ptr += datatype.getSize();
|
||||
}
|
||||
|
||||
H5Dvlen_reclaim(datatype.getId(), dataspace.getId(), H5P_DEFAULT, buffer);
|
||||
delete[] buffer;
|
||||
|
||||
dataspace.close();
|
||||
datatype.close();
|
||||
names.close();
|
||||
schema_group.close();
|
||||
}
|
||||
|
||||
size_t instance_name(void* data, H5::CompType* dt) {
|
||||
hsize_t pair[2];
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
H5::DataType mt = dt->getMemberDataType(i);
|
||||
size_t offset = dt->getMemberOffset(i);
|
||||
pair[i] = read<int>((uint8_t*)data + offset, &mt);
|
||||
}
|
||||
|
||||
const std::string& nm = dataset_names_[pair[0]];
|
||||
|
||||
H5::DataSet dataset = file_.openDataSet("population/" + nm + "_instances");
|
||||
H5::CompType datatype = dataset.getCompType();
|
||||
H5::DataSpace dataspace = dataset.getSpace();
|
||||
if (dataspace.getSimpleExtentNdims() != 1) {
|
||||
throw std::runtime_error("Expected one-dimensional data");
|
||||
}
|
||||
dataspace.selectElements(H5S_SELECT_SET, 1, pair + 1);
|
||||
const hsize_t one = 1;
|
||||
H5::DataSpace memspace(1, &one);
|
||||
|
||||
uint8_t* buffer = new uint8_t[datatype.getSize()];
|
||||
dataset.read(buffer, datatype, memspace, dataspace);
|
||||
|
||||
int idx = datatype.getMemberIndex("Entity-Instance-Identifier");
|
||||
size_t inst_name_offset = datatype.getMemberOffset(idx);
|
||||
H5::DataType member_type = datatype.getMemberDataType(idx);
|
||||
|
||||
size_t inst_name = read<int>((uint8_t*)buffer + inst_name_offset, &member_type);
|
||||
|
||||
member_type.close();
|
||||
memspace.close();
|
||||
datatype.close();
|
||||
dataspace.close();
|
||||
dataset.close();
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
return inst_name;
|
||||
}
|
||||
};
|
||||
|
||||
void visit(instance_resolver& resolver, std::ostream& output, void* buffer, H5::DataType* dt, const std::string& name = no_name, const std::bitset<64>& bitmask = many_trues) {
|
||||
if (dt->getClass() == H5T_COMPOUND) {
|
||||
|
||||
// std::vector<IfcParse::entity::attribute*> schema_attributes;
|
||||
std::vector<bool> derived;
|
||||
std::vector<std::string> attribute_names;
|
||||
std::vector<std::string>::const_iterator attribute_name_it;
|
||||
if (&name != &no_name) {
|
||||
auto entity = get_schema().declaration_by_name(IfcSchema::Type::FromString(boost::to_upper_copy(name)))->as_entity();
|
||||
auto attributes = entity->all_attributes();
|
||||
std::transform(attributes.begin(), attributes.end(), std::back_inserter(attribute_names), [](const IfcParse::entity::attribute* attr) {
|
||||
return attr->name();
|
||||
});
|
||||
derived = entity->derived();
|
||||
attribute_name_it = attribute_names.begin();
|
||||
}
|
||||
|
||||
H5::CompType* ct = (H5::CompType*) dt;
|
||||
const auto is_ref = is_instance_ref(dt);
|
||||
if (is_ref) {
|
||||
output << "#" << resolver.instance_name(buffer, ct);
|
||||
} else {
|
||||
int ifc_idx = 0;
|
||||
const std::bitset<64>* mask = &bitmask;
|
||||
std::string select_valuation;
|
||||
bool is_instance = false;
|
||||
bool is_select = false;
|
||||
bool is_selected_simple_type = false;
|
||||
bool select_valuation_encountered = false;
|
||||
|
||||
for (int i = 0; i < ct->getNmembers(); ++i) {
|
||||
const std::string member_name = ct->getMemberName(i);
|
||||
|
||||
const size_t offs = ct->getMemberOffset(i);
|
||||
void* member_ptr = (uint8_t*)buffer + offs;
|
||||
H5::DataType member_type = ct->getMemberDataType(i);
|
||||
|
||||
if (member_name == "set_unset_bitmap") {
|
||||
mask = new std::bitset<64>(read<int>(member_ptr, &member_type));
|
||||
} else if (member_name == "Entity-Instance-Identifier") {
|
||||
is_instance = true;
|
||||
output << "#" << read<int>(member_ptr, &member_type) << "=" << boost::to_upper_copy(name) << "(";
|
||||
} else if (member_name == "type_code") {
|
||||
is_select = true;
|
||||
IfcSchema::Type::Enum ty = (IfcSchema::Type::Enum) read<int>(member_ptr, &member_type);
|
||||
auto decl = get_schema().declaration_by_name(ty);
|
||||
if (decl->as_entity()) {
|
||||
select_valuation = "instance-value";
|
||||
} else {
|
||||
std::string type_string = IfcSchema::Type::ToString(ty);
|
||||
boost::to_upper(type_string);
|
||||
output << type_string << "(";
|
||||
IfcParse::Hdf5Settings settings;
|
||||
select_valuation = type_mapper(nullptr, nullptr, settings).make_select_leaf(decl, no_instances).first;
|
||||
is_selected_simple_type = true;
|
||||
}
|
||||
} else {
|
||||
if (is_select) {
|
||||
if (member_name == select_valuation) {
|
||||
visit(resolver, output, member_ptr, &member_type, name, many_trues);
|
||||
select_valuation_encountered = true;
|
||||
}
|
||||
} else {
|
||||
while (member_name != *attribute_name_it) {
|
||||
if (ifc_idx) {
|
||||
output << ",";
|
||||
}
|
||||
attribute_name_it++;
|
||||
ifc_idx++;
|
||||
output << "*";
|
||||
}
|
||||
if (ifc_idx) {
|
||||
output << ",";
|
||||
}
|
||||
if ((*mask)[ifc_idx]) {
|
||||
visit(resolver, output, member_ptr, &member_type, name, many_trues);
|
||||
} else {
|
||||
output << "$";
|
||||
}
|
||||
ifc_idx++;
|
||||
attribute_name_it++;
|
||||
}
|
||||
}
|
||||
member_type.close();
|
||||
}
|
||||
if (is_select && !select_valuation_encountered) {
|
||||
throw std::runtime_error("Select valuation not encountered in compound");
|
||||
}
|
||||
if (mask != &many_trues) {
|
||||
delete mask;
|
||||
}
|
||||
if (is_selected_simple_type || is_instance) {
|
||||
output << ")";
|
||||
if (is_instance) {
|
||||
output << ";" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (dt->getClass() == H5T_VLEN) {
|
||||
hvl_t* ht = (hvl_t*)buffer;
|
||||
H5::VarLenType* vt = (H5::VarLenType*) dt;
|
||||
H5::DataType dt2 = vt->getSuper();
|
||||
output << "(";
|
||||
for (size_t i = 0; i < ht->len; ++i) {
|
||||
if (i) {
|
||||
output << ",";
|
||||
}
|
||||
visit(resolver, output, (uint8_t*)ht->p + i * dt2.getSize(), &dt2);
|
||||
}
|
||||
output << ")";
|
||||
dt2.close();
|
||||
} else if (dt->getClass() == H5T_STRING) {
|
||||
const bool is_varlen = H5Tis_variable_str(dt->getId()) > 0;
|
||||
if (is_varlen) {
|
||||
const char* c = read<const char*>(buffer, dt);
|
||||
output << "'" << c << "'";
|
||||
} else {
|
||||
throw std::runtime_error("blurgfh");
|
||||
}
|
||||
} else if (dt->getClass() == H5T_INTEGER) {
|
||||
output << read<int>(buffer, dt);
|
||||
} else if (dt->getClass() == H5T_FLOAT) {
|
||||
output << IfcWrite::format(read<double>(buffer, dt));
|
||||
} else if (dt->getClass() == H5T_ENUM) {
|
||||
const char *enum_value;
|
||||
char *to_free;
|
||||
enum_value = to_free = H5Tget_member_name(dt->getId(), read<int>(buffer, dt));
|
||||
char substr[2] = { 0,0 };
|
||||
const char BOOLEAN[] = "BOOLEAN-";
|
||||
const char LOGICAL[] = "LOGICAL-";
|
||||
if (strstr(enum_value, BOOLEAN) || strstr(enum_value, LOGICAL)) {
|
||||
// Hack to convert BOOLEAN-TRUE et al to T
|
||||
// Boolean and logical are of the same length coincedentally
|
||||
substr[0] = enum_value[strlen(BOOLEAN)];
|
||||
enum_value = substr;
|
||||
}
|
||||
output << "." << enum_value << ".";
|
||||
H5free_memory(to_free);
|
||||
} else {
|
||||
throw std::runtime_error("Unexpected datatype encountered");
|
||||
}
|
||||
}
|
||||
|
||||
struct hdf5_output_info {
|
||||
H5::H5File& file;
|
||||
std::ostream& output;
|
||||
};
|
||||
|
||||
herr_t iterate(hid_t, const char *name_, const H5O_info_t *object_info, void *op_data) {
|
||||
H5::H5File& f = ((hdf5_output_info*)op_data)->file;
|
||||
std::ostream& output = ((hdf5_output_info*)op_data)->output;
|
||||
|
||||
instance_resolver resolver(f);
|
||||
|
||||
if (object_info->type == H5O_TYPE_DATASET) {
|
||||
std::string name = name_;
|
||||
|
||||
H5::DataSet dataset = f.openDataSet(name);
|
||||
H5::DataType datatype = dataset.getDataType();
|
||||
H5::DataSpace dataspace = dataset.getSpace();
|
||||
if (dataspace.getSimpleExtentNdims() != 1) {
|
||||
throw std::runtime_error("Expected one-dimensional data");
|
||||
}
|
||||
hsize_t dim;
|
||||
dataspace.getSimpleExtentDims(&dim, NULL);
|
||||
uint8_t* buffer, *ptr;
|
||||
buffer = ptr = new uint8_t[(size_t) dim * datatype.getSize()];
|
||||
dataset.read(buffer, datatype);
|
||||
|
||||
auto slash = name.find_last_of('/');
|
||||
if (slash != std::string::npos) {
|
||||
name = name.substr(slash + 1);
|
||||
}
|
||||
auto under = name.find('_');
|
||||
if (under != std::string::npos) {
|
||||
name = name.substr(0, under);
|
||||
}
|
||||
|
||||
while (dim--) {
|
||||
visit(resolver, output, ptr, &datatype, name);
|
||||
ptr += datatype.getSize();
|
||||
}
|
||||
|
||||
datatype.close();
|
||||
dataspace.close();
|
||||
dataset.close();
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void IfcParse::IfcHdf5File::convert_to_spf(const std::string& name, std::ostream& output) {
|
||||
H5::H5File f(name, H5F_ACC_RDONLY);
|
||||
hdf5_output_info info{ f,output };
|
||||
H5Ovisit(f.getId(), H5_INDEX_NAME, H5_ITER_NATIVE, iterate, &info);
|
||||
}
|
||||
|
||||
@@ -159,6 +159,8 @@ namespace IfcParse {
|
||||
write_schema(schema_, ifcfile_);
|
||||
write_population(ifcfile_);
|
||||
};
|
||||
|
||||
static void convert_to_spf(const std::string& name, std::ostream& output);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+56
-55
@@ -326,6 +326,55 @@ public:
|
||||
int operator()(const IfcEntityListList::ptr& i) const { return i->size(); }
|
||||
};
|
||||
|
||||
// The REAL token definition from the IFC SPF standard does not necessarily match
|
||||
// the output of the C++ ostream formatting operation.
|
||||
// REAL = [ SIGN ] DIGIT { DIGIT } "." { DIGIT } [ "E" [ SIGN ] DIGIT { DIGIT } ] .
|
||||
std::string IfcWrite::format(double d) {
|
||||
std::ostringstream oss;
|
||||
oss.imbue(std::locale::classic());
|
||||
oss << std::setprecision(std::numeric_limits<double>::digits10 + 1) << d;
|
||||
const std::string str = oss.str();
|
||||
oss.str("");
|
||||
std::string::size_type e = str.find('e');
|
||||
if (e == std::string::npos) {
|
||||
e = str.find('E');
|
||||
}
|
||||
const std::string mantissa = str.substr(0, e);
|
||||
oss << mantissa;
|
||||
if (mantissa.find('.') == std::string::npos) {
|
||||
oss << ".";
|
||||
}
|
||||
if (e != std::string::npos) {
|
||||
oss << "E";
|
||||
oss << str.substr(e + 1);
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string IfcWrite::format(const boost::dynamic_bitset<>& b) {
|
||||
std::ostringstream oss;
|
||||
oss.imbue(std::locale::classic());
|
||||
oss.put('"');
|
||||
oss << std::hex << std::setw(1);
|
||||
unsigned c = (unsigned)b.size();
|
||||
unsigned n = (4 - (c % 4)) & 3;
|
||||
oss << n;
|
||||
for (unsigned i = 0; i < c + n;) {
|
||||
unsigned accum = 0;
|
||||
for (int j = 0; j < 4; ++j, ++i) {
|
||||
unsigned bit = i < n ? 0 : b.test(c - i + n - 1) ? 1 : 0;
|
||||
accum |= bit << (3 - j);
|
||||
}
|
||||
oss << accum;
|
||||
}
|
||||
oss.put('"');
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string IfcWrite::format(bool b) {
|
||||
return b ? ".T." : ".F.";
|
||||
}
|
||||
|
||||
class StringBuilderVisitor : public boost::static_visitor<void> {
|
||||
private:
|
||||
StringBuilderVisitor(const StringBuilderVisitor&); //N/A
|
||||
@@ -340,55 +389,7 @@ private:
|
||||
}
|
||||
data << ")";
|
||||
}
|
||||
// The REAL token definition from the IFC SPF standard does not necessarily match
|
||||
// the output of the C++ ostream formatting operation.
|
||||
// REAL = [ SIGN ] DIGIT { DIGIT } "." { DIGIT } [ "E" [ SIGN ] DIGIT { DIGIT } ] .
|
||||
std::string format_double(const double& d) {
|
||||
std::ostringstream oss;
|
||||
oss.imbue(std::locale::classic());
|
||||
oss << std::setprecision(std::numeric_limits<double>::digits10) << d;
|
||||
const std::string str = oss.str();
|
||||
oss.str("");
|
||||
std::string::size_type e = str.find('e');
|
||||
if (e == std::string::npos) {
|
||||
e = str.find('E');
|
||||
}
|
||||
const std::string mantissa = str.substr(0,e);
|
||||
oss << mantissa;
|
||||
if (mantissa.find('.') == std::string::npos) {
|
||||
oss << ".";
|
||||
}
|
||||
if (e != std::string::npos) {
|
||||
oss << "E";
|
||||
oss << str.substr(e+1);
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string format_bool(bool b) {
|
||||
return b ? ".T." : ".F.";
|
||||
}
|
||||
|
||||
std::string format_binary(const boost::dynamic_bitset<>& b) {
|
||||
std::ostringstream oss;
|
||||
oss.imbue(std::locale::classic());
|
||||
oss.put('"');
|
||||
oss << std::hex << std::setw(1);
|
||||
unsigned c = (unsigned)b.size();
|
||||
unsigned n = (4 - (c % 4)) & 3;
|
||||
oss << n;
|
||||
for (unsigned i = 0; i < c + n;) {
|
||||
unsigned accum = 0;
|
||||
for (int j = 0; j < 4; ++j, ++i) {
|
||||
unsigned bit = i < n ? 0 : b.test(c - i + n - 1) ? 1 : 0;
|
||||
accum |= bit << (3-j);
|
||||
}
|
||||
oss << accum;
|
||||
}
|
||||
oss.put('"');
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
bool upper;
|
||||
public:
|
||||
StringBuilderVisitor(std::ostringstream& stream, bool upper = false)
|
||||
@@ -396,9 +397,9 @@ public:
|
||||
void operator()(const boost::none_t& /*i*/) { data << "$"; }
|
||||
void operator()(const IfcWriteArgument::Derived& /*i*/) { data << "*"; }
|
||||
void operator()(const int& i) { data << i; }
|
||||
void operator()(const bool& i) { data << format_bool(i); }
|
||||
void operator()(const double& i) { data << format_double(i); }
|
||||
void operator()(const boost::dynamic_bitset<>& i) { data << format_binary(i); }
|
||||
void operator()(const bool& i) { data << IfcWrite::format(i); }
|
||||
void operator()(const double& i) { data << IfcWrite::format(i); }
|
||||
void operator()(const boost::dynamic_bitset<>& i) { data << IfcWrite::format(i); }
|
||||
void operator()(const std::string& i) {
|
||||
std::string s = i;
|
||||
if (upper) {
|
||||
@@ -470,7 +471,7 @@ void StringBuilderVisitor::serialize(const std::vector<double>& i) {
|
||||
data << "(";
|
||||
for (std::vector<double>::const_iterator it = i.begin(); it != i.end(); ++it) {
|
||||
if (it != i.begin()) data << ",";
|
||||
data << format_double(*it);
|
||||
data << IfcWrite::format(*it);
|
||||
}
|
||||
data << ")";
|
||||
}
|
||||
@@ -480,7 +481,7 @@ void StringBuilderVisitor::serialize(const std::vector<bool>& i) {
|
||||
data << "(";
|
||||
for (std::vector<bool>::const_iterator it = i.begin(); it != i.end(); ++it) {
|
||||
if (it != i.begin()) data << ",";
|
||||
data << format_bool(*it);
|
||||
data << IfcWrite::format(*it);
|
||||
}
|
||||
data << ")";
|
||||
}
|
||||
@@ -490,7 +491,7 @@ void StringBuilderVisitor::serialize(const std::vector< boost::dynamic_bitset<>
|
||||
data << "(";
|
||||
for (std::vector< boost::dynamic_bitset<> >::const_iterator it = i.begin(); it != i.end(); ++it) {
|
||||
if (it != i.begin()) data << ",";
|
||||
data << format_binary(*it);
|
||||
data << IfcWrite::format(*it);
|
||||
}
|
||||
data << ")";
|
||||
}
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
|
||||
namespace IfcWrite {
|
||||
|
||||
std::string format(bool b);
|
||||
std::string format(double d);
|
||||
std::string format(const boost::dynamic_bitset<>& b);
|
||||
|
||||
/// This class is a writable container for attributes. A fundamental
|
||||
/// difference with the attribute types counterparts defined in the
|
||||
/// IfcParse namespace is that this class has a Boost.Variant member
|
||||
|
||||
Reference in New Issue
Block a user