From addef5dfa307b9ef4c6a3a2546a40bf432106b55 Mon Sep 17 00:00:00 2001 From: johltn Date: Fri, 12 Feb 2021 17:32:43 +0100 Subject: [PATCH] Create HdfSerializer based on ObjSerializer --- cmake/CMakeLists.txt | 2 +- src/ifcconvert/IfcConvert.cpp | 10 +- src/serializers/HdfSerializer.cpp | 200 ++++++++++++++++++++++++++++++ src/serializers/HdfSerializer.h | 51 ++++++++ 4 files changed, 261 insertions(+), 2 deletions(-) create mode 100644 src/serializers/HdfSerializer.cpp create mode 100644 src/serializers/HdfSerializer.h diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 38503c4ba1..b7d1bd6192 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -644,7 +644,7 @@ set(SERIALIZERS_S_FILES ${SERIALIZERS_S_H_FILES} ${SERIALIZERS_S_CPP_FILES}) foreach(s ${SCHEMA_VERSIONS}) add_library(Serializers_ifc${s} STATIC ${SERIALIZERS_S_FILES}) set_target_properties(Serializers_ifc${s} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${s} ${CONVERT_PRECISION}") - TARGET_LINK_LIBRARIES(Serializers_ifc${s} IfcGeom ${OPENCASCADE_LIBRARIES}) + TARGET_LINK_LIBRARIES(Serializers_ifc${s} IfcGeom ${OPENCASCADE_LIBRARIES} ${HDF5_LIBRARIES}) endforeach() add_library(Serializers ${SERIALIZERS_FILES}) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index c4c812d973..fabcc477fe 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -28,6 +28,7 @@ #include "../serializers/ColladaSerializer.h" #include "../serializers/GltfSerializer.h" +#include "../serializers/HdfSerializer.h" #include "../serializers/IgesSerializer.h" #include "../serializers/StepSerializer.h" #include "../serializers/WavefrontObjSerializer.h" @@ -637,6 +638,7 @@ int main(int argc, char** argv) { STP = IfcUtil::path::from_utf8(".stp"), IGS = IfcUtil::path::from_utf8(".igs"), SVG = IfcUtil::path::from_utf8(".svg"), + HDF = IfcUtil::path::from_utf8(".hdf"), XML = IfcUtil::path::from_utf8(".xml"), IFC = IfcUtil::path::from_utf8(".ifc"); @@ -794,7 +796,13 @@ int main(int argc, char** argv) { } else if (output_extension == SVG) { settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), settings); - } else { + } + else if (output_extension == HDF) { + const path_t mtl_filename = change_extension(output_filename, MTL); + serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), IfcUtil::path::to_utf8(mtl_filename), settings); + } + + else { cerr_ << "[Error] Unknown output filename extension '" << output_extension << "'\n"; write_log(!quiet); print_usage(); diff --git a/src/serializers/HdfSerializer.cpp b/src/serializers/HdfSerializer.cpp new file mode 100644 index 0000000000..dd999e3134 --- /dev/null +++ b/src/serializers/HdfSerializer.cpp @@ -0,0 +1,200 @@ +/******************************************************************************** + * * + * This file is part of IfcOpenShell. * + * * + * IfcOpenShell is free software: you can redistribute it and/or modify * + * it under the terms of the Lesser GNU General Public License as published by * + * the Free Software Foundation, either version 3.0 of the License, or * + * (at your option) any later version. * + * * + * IfcOpenShell is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * Lesser GNU General Public License for more details. * + * * + * You should have received a copy of the Lesser GNU General Public License * + * along with this program. If not, see . * + * * + ********************************************************************************/ + + +#include "HdfSerializer.h" + +#include "H5Cpp.h" + +#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h" + +#include "../ifcparse/utils.h" + +#include +#include + +HdfSerializer::HdfSerializer(const std::string& obj_filename, const std::string& mtl_filename, const SerializerSettings& settings) + : GeometrySerializer(settings) + , mtl_filename(mtl_filename) + , obj_stream(IfcUtil::path::from_utf8(obj_filename).c_str()) + , mtl_stream(IfcUtil::path::from_utf8(mtl_filename).c_str()) + , vcount_total(1) +{ + obj_stream << std::setprecision(settings.precision); + mtl_stream << std::setprecision(settings.precision); +} + +bool HdfSerializer::ready() { + return obj_stream.is_open() && mtl_stream.is_open(); +} + +void HdfSerializer::writeHeader() { + obj_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n"; +#ifdef WIN32 + const char dir_separator = '\\'; +#else + const char dir_separator = '/'; +#endif + std::string mtl_basename = mtl_filename; + std::string::size_type slash = mtl_basename.find_last_of(dir_separator); + if (slash != std::string::npos) { + mtl_basename = mtl_basename.substr(slash+1); + } + obj_stream << "mtllib " << mtl_basename << "\n"; + mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n"; +} + +void HdfSerializer::writeMaterial(const IfcGeom::Material& style) +{ + std::string material_name = (settings().get(SerializerSettings::USE_MATERIAL_NAMES) + ? style.original_name() : style.name()); + IfcUtil::sanitate_material_name(material_name); + mtl_stream << "newmtl " << material_name << "\n"; + + if (style.hasDiffuse()) { + const double* diffuse = style.diffuse(); + mtl_stream << "Kd " << diffuse[0] << " " << diffuse[1] << " " << diffuse[2] << "\n"; + } + if (style.hasSpecular()) { + const double* specular = style.specular(); + mtl_stream << "Ks " << specular[0] << " " << specular[1] << " " << specular[2] << "\n"; + } + if (style.hasSpecularity()) { + mtl_stream << "Ns " << style.specularity() << "\n"; + } + if (style.hasTransparency()) { + const double transparency = 1.0 - style.transparency(); + if (transparency < 1) { + mtl_stream << "d " << transparency << "\n"; + } + } +} + +void HdfSerializer::write(const IfcGeom::TriangulationElement* o) +{ + + int a; + H5::H5File ff; + + + obj_stream << "g " << object_id(o) << "\n"; + obj_stream << "s 1" << "\n"; + const bool isyup = settings().get(SerializerSettings::USE_Y_UP); + + const IfcGeom::Representation::Triangulation& mesh = o->geometry(); + + const int vcount = (int)mesh.verts().size() / 3; + for ( std::vector::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) { + const real_t x = *(it++); + const real_t y = *(it++); + const real_t z = *(it++); + + if (isyup) { + obj_stream << "v " << x << " " << z << " " << -y << "\n"; + } else { + obj_stream << "v " << x << " " << y << " " << z << "\n"; + } + } + + for ( std::vector::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) { + const real_t x = *(it++); + const real_t y = *(it++); + const real_t z = *(it++); + obj_stream << "vn " << x << " " << y << " " << z << "\n"; + } + + for (std::vector::const_iterator it = mesh.uvs().begin(); it != mesh.uvs().end();) { + const real_t u = *it++; + const real_t v = *it++; + obj_stream << "vt " << u << " " << v << "\n"; + } + + int previous_material_id = -2; + std::vector::const_iterator material_it = mesh.material_ids().begin(); + + const bool has_uvs = !mesh.uvs().empty(); + const bool has_normals = !mesh.normals().empty(); + for ( std::vector::const_iterator it = mesh.faces().begin(); it != mesh.faces().end(); ) { + + const int material_id = *(material_it++); + if (material_id != previous_material_id) { + const IfcGeom::Material& material = mesh.materials()[material_id]; + std::string material_name = (settings().get(SerializerSettings::USE_MATERIAL_NAMES) + ? material.original_name() : material.name()); + IfcUtil::sanitate_material_name(material_name); + obj_stream << "usemtl " << material_name << "\n"; + if (materials.find(material_name) == materials.end()) { + writeMaterial(material); + materials.insert(material_name); + } + previous_material_id = material_id; + } + + const int v1 = *(it++)+vcount_total; + const int v2 = *(it++)+vcount_total; + const int v3 = *(it++)+vcount_total; + + if (has_normals && has_uvs) { + obj_stream << "f " << v1 << "/" << v1 << "/" << v1 << " " + << v2 << "/" << v2 << "/" << v2 << " " + << v3 << "/" << v3 << "/" << v3 << "\n"; + } else if (has_normals) { + obj_stream << "f " << v1 << "//" << v1 << " " + << v2 << "//" << v2 << " " + << v3 << "//" << v3 << "\n"; + } else { + obj_stream << "f " << v1 << " " << v2 << " " << v3 << "\n"; + } + + } + + std::set faces_set (mesh.faces().begin(), mesh.faces().end()); + const std::vector& edges = mesh.edges(); + + for ( std::vector::const_iterator it = edges.begin(); it != edges.end(); ) { + const int i1 = *(it++); + const int i2 = *(it++); + + if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) { + continue; + } + + const int material_id = *(material_it++); + + if (material_id != previous_material_id) { + const IfcGeom::Material& material = mesh.materials()[material_id]; + std::string material_name = (settings().get(SerializerSettings::USE_MATERIAL_NAMES) + ? material.original_name() : material.name()); + IfcUtil::sanitate_material_name(material_name); + obj_stream << "usemtl " << material_name << "\n"; + if (materials.find(material_name) == materials.end()) { + writeMaterial(material); + materials.insert(material_name); + } + previous_material_id = material_id; + } + + const int v1 = i1 + vcount_total; + const int v2 = i2 + vcount_total; + + obj_stream << "l " << v1 << " " << v2 << "\n"; + } + + vcount_total += vcount; +} diff --git a/src/serializers/HdfSerializer.h b/src/serializers/HdfSerializer.h new file mode 100644 index 0000000000..42bba9addd --- /dev/null +++ b/src/serializers/HdfSerializer.h @@ -0,0 +1,51 @@ +/******************************************************************************** + * * + * This file is part of IfcOpenShell. * + * * + * IfcOpenShell is free software: you can redistribute it and/or modify * + * it under the terms of the Lesser GNU General Public License as published by * + * the Free Software Foundation, either version 3.0 of the License, or * + * (at your option) any later version. * + * * + * IfcOpenShell is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * Lesser GNU General Public License for more details. * + * * + * You should have received a copy of the Lesser GNU General Public License * + * along with this program. If not, see . * + * * + ********************************************************************************/ + +#ifndef HdfSERIALIZER_H +#define HdfSERIALIZER_H + +#include +#include +#include + +#include "../serializers/GeometrySerializer.h" + +// http://people.sc.fsu.edu/~jburkardt/txt/obj_format.txt +class HdfSerializer : public GeometrySerializer { +private: + const std::string mtl_filename; + std::ofstream obj_stream; + std::ofstream mtl_stream; + unsigned int vcount_total; + std::set materials; +public: + HdfSerializer(const std::string& obj_filename, const std::string& mtl_filename, const SerializerSettings& settings); + virtual ~HdfSerializer() {} + bool ready(); + void writeHeader(); + void writeMaterial(const IfcGeom::Material& style); + void write(const IfcGeom::TriangulationElement* o); + void write(const IfcGeom::BRepElement* /*o*/) {} + void finalize() {} + bool isTesselated() const { return true; } + void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {} + void setFile(IfcParse::IfcFile*) {} +}; + +#endif