From 5d4ff0b54a76e298e124118c695486cbf049b9d1 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 24 Mar 2013 10:48:39 +0000 Subject: [PATCH] First push of a more all-round geometrical file conversion utility --- cmake/CMakeLists.txt | 11 +- src/ifcconvert/ColladaSerializer.cpp | 206 +++++++++++++ src/ifcconvert/ColladaSerializer.h | 145 +++++++++ src/ifcconvert/GeometrySerializer.h | 36 +++ src/ifcconvert/IfcConvert.cpp | 288 ++++++++++++++++++ src/ifcconvert/IgesSerializer.h | 47 +++ src/ifcconvert/OpenCascadeBasedSerializer.cpp | 56 ++++ src/ifcconvert/OpenCascadeBasedSerializer.h | 46 +++ src/ifcconvert/StepSerializer.h | 47 +++ .../SurfaceStyle.h} | 82 ++--- src/ifcconvert/WavefrontObjSerializer.cpp | 84 +++++ src/ifcconvert/WavefrontObjSerializer.h | 55 ++++ src/ifcgeom/IfcGeomObjects.cpp | 203 +++++++----- src/ifcgeom/IfcGeomObjects.h | 100 +++++- src/ifcobj/IfcObj.cpp | 127 -------- src/ifcobj/Materials.cpp | 5 - src/ifcparse/IfcUtil.cpp | 5 + src/ifcparse/IfcUtil.h | 1 + win/{IfcObj.vcproj => IfcConvert.vcproj} | 48 ++- win/IfcOpenShell.sln | 2 +- 20 files changed, 1330 insertions(+), 264 deletions(-) create mode 100644 src/ifcconvert/ColladaSerializer.cpp create mode 100644 src/ifcconvert/ColladaSerializer.h create mode 100644 src/ifcconvert/GeometrySerializer.h create mode 100644 src/ifcconvert/IfcConvert.cpp create mode 100644 src/ifcconvert/IgesSerializer.h create mode 100644 src/ifcconvert/OpenCascadeBasedSerializer.cpp create mode 100644 src/ifcconvert/OpenCascadeBasedSerializer.h create mode 100644 src/ifcconvert/StepSerializer.h rename src/{ifcobj/ObjMaterials.h => ifcconvert/SurfaceStyle.h} (51%) create mode 100644 src/ifcconvert/WavefrontObjSerializer.cpp create mode 100644 src/ifcconvert/WavefrontObjSerializer.h delete mode 100644 src/ifcobj/IfcObj.cpp delete mode 100644 src/ifcobj/Materials.cpp rename win/{IfcObj.vcproj => IfcConvert.vcproj} (75%) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index bb2f42a687..0925215314 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -125,9 +125,14 @@ TARGET_LINK_LIBRARIES(IfcGeom IfcParse) LINK_DIRECTORIES (${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS}) -ADD_EXECUTABLE(IfcObj ../src/ifcobj/IfcObj.cpp) +ADD_EXECUTABLE(IfcConvert + ../src/ifcconvert/ColladaSerializer.cpp + ../src/ifcconvert/IfcConvert.cpp + ../src/ifcconvert/OpenCascadeBasedSerializer.cpp + ../src/ifcconvert/WavefrontObjSerializer.cpp +) -TARGET_LINK_LIBRARIES (IfcObj IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet) +TARGET_LINK_LIBRARIES (IfcConvert IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES) # Build python wrapper using separate CMakeLists.txt ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap) @@ -171,5 +176,5 @@ SET(include_files_parse ) INSTALL(FILES ${include_files_geom} DESTINATION include/ifcgeom) INSTALL(FILES ${include_files_parse} DESTINATION include/ifcparse) -INSTALL(TARGETS IfcObj DESTINATION bin) +INSTALL(TARGETS IfcConvert DESTINATION bin) INSTALL(TARGETS IfcParse IfcGeom DESTINATION lib) diff --git a/src/ifcconvert/ColladaSerializer.cpp b/src/ifcconvert/ColladaSerializer.cpp new file mode 100644 index 0000000000..ec8ebbb77c --- /dev/null +++ b/src/ifcconvert/ColladaSerializer.cpp @@ -0,0 +1,206 @@ +/******************************************************************************** + * * + * 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 "ColladaSerializer.h" + +void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector& floats, const char* coords /* = "XYZ" */) { + COLLADASW::FloatSource source(mSW); + source.setId(mesh_id + suffix); + source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX); + source.setAccessorStride(strlen(coords)); + source.setAccessorCount(floats.size() / 3); + for (unsigned int i = 0; i < source.getAccessorStride(); ++i) { + source.getParameterNameList().push_back(std::string(1, coords[i])); + } + source.prepareToAppendValues(); + for (std::vector::const_iterator it = floats.begin(); it != floats.end(); ++it) { + source.appendValues(*it); + } + source.finish(); +} + +void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::vector& positions, const std::vector& normals, const std::vector& indices) { + openMesh(mesh_id); + + addFloatSource(mesh_id, COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX, positions); + if (!normals.empty()) { + // The normals vector can be empty for example when the WELD_VERTICES setting is used. + // IfcOpenShell does not provide them with multiple face normals collapsed into a single vertex. + addFloatSource(mesh_id, COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, normals); + } + + COLLADASW::VerticesElement vertices(mSW); + vertices.setId(mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX ); + vertices.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::POSITION, "#" + mesh_id + COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX)); + vertices.add(); + + COLLADASW::Triangles triangles(mSW); + triangles.setCount(indices.size() / 3); + int offset = 0; + triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++ ) ); + if (!normals.empty()) { + triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++ ) ); + } + triangles.prepareToAppendValues(); + for (auto it = indices.begin(); it != indices.end(); ++it) { + const auto& idx = *it; + if (!normals.empty()) { + triangles.appendValues(idx, idx); + } else { + triangles.appendValues(idx); + } + } + triangles.finish(); + + closeMesh(); + closeGeometry(); +} + +void ColladaSerializer::ColladaExporter::ColladaGeometries::close() { + closeLibrary(); +} + +void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& node_id, const std::string& node_name, const std::string& geom_id, const std::string& material_id, const std::vector& matrix) { + if (!scene_opened) { + openVisualScene(scene_id); + scene_opened = true; + } + + COLLADASW::Node node(mSW); + node.setNodeId(node_id); + node.setNodeName(node_name); + node.setType(COLLADASW::Node::DEFAULT); + + // The matrix attribute of an entity is basically a 4x3 representation of its ObjectPlacement. + // Note that this placement is absolute, ie it is multiplied with all parent placements. + double matrix_array[4][4] = { + {matrix[0], matrix[3], matrix[6], matrix[ 9]}, + {matrix[1], matrix[4], matrix[7], matrix[10]}, + {matrix[2], matrix[5], matrix[8], matrix[11]}, + { 0, 0, 0, 1} + }; + + node.start(); + node.addMatrix(matrix_array); + + COLLADASW::InstanceGeometry instanceGeometry(mSW); + instanceGeometry.setUrl ("#" + geom_id); + COLLADASW::InstanceMaterial material ("ColorMaterial", "#" + material_id); + instanceGeometry.getBindMaterial().getInstanceMaterialList().push_back(material); + instanceGeometry.add(); + node.end(); +} + +void ColladaSerializer::ColladaExporter::ColladaScene::write() { + if (scene_opened) { + closeVisualScene(); + closeLibrary(); + + COLLADASW::Scene scene (mSW, COLLADASW::URI ("#" + scene_id)); + scene.add(); + } +} + +void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const SurfaceStyle& style) { + openEffect(style.Name() + "-fx"); + COLLADASW::EffectProfile effect(mSW); + effect.setShaderType(COLLADASW::EffectProfile::LAMBERT); + effect.setDiffuse(COLLADASW::ColorOrTexture(COLLADASW::Color(style.Diffuse().R(),style.Diffuse().G(),style.Diffuse().B()))); + addEffectProfile(effect); +} + +void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close() { + closeLibrary(); +} + +void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const SurfaceStyle& style) { + if (!contains(style.Name())) { + effects.write(style); + surface_styles.push_back(style); + } +} + +bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const std::string& name) { + for (auto it = surface_styles.begin(); it != surface_styles.end(); ++it) { + if (it->Name() == name) return true; + } + return false; +} + +void ColladaSerializer::ColladaExporter::ColladaMaterials::write() { + effects.close(); + for (auto it = surface_styles.begin(); it != surface_styles.end(); ++it) { + const std::string& material_name = it->Name(); + openMaterial(material_name); + addInstanceEffect("#" + material_name + "-fx"); + closeLibrary(); + } +} + +void ColladaSerializer::ColladaExporter::startDocument() { + stream.startDocument(); + + COLLADASW::Asset asset(&stream); + asset.getContributor().mAuthoringTool = std::string("IfcOpenShell ") + IFCOPENSHELL_VERSION; + // TODO: Get the appropriate unit from the IFC file. + asset.setUnit("meter", 1.0); + asset.setUpAxisType(COLLADASW::Asset::Z_UP); + asset.add(); +} + +void ColladaSerializer::ColladaExporter::writeTesselated(const std::string& type, int obj_id, const std::vector& matrix, const std::vector& vertices, const std::vector& normals, const std::vector& indices) { + if (!materials.contains(type)) materials.add(GetDefaultMaterial(type)); + deferreds.push_back(DeferedObject(type, obj_id, matrix, vertices, normals, indices)); +} + +void ColladaSerializer::ColladaExporter::endDocument() { + // In fact due the XML based nature of Collada and its dependency on library nodes, + // only at this point all objects are written to the stream. + materials.write(); + for (auto it = deferreds.begin(); it != deferreds.end(); ++it) { + std::stringstream ss; ss << "object" << it->obj_id; + const std::string object_id = ss.str(); + geometries.write(object_id, it->vertices, it->normals, it->indices); + } + geometries.close(); + for (auto it = deferreds.begin(); it != deferreds.end(); ++it) { + std::stringstream ss; ss << "object" << it->obj_id; + const std::string object_id = ss.str(); + scene.add(object_id, object_id, object_id, it->type, it->matrix); + } + scene.write(); + stream.endDocument(); +} + +bool ColladaSerializer::ready() { + return true; +} + +void ColladaSerializer::writeHeader() { + exporter.startDocument(); +} + +void ColladaSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject* o) { + exporter.writeTesselated(o->type, o->id, o->matrix, o->mesh->verts, o->mesh->normals, o->mesh->faces); +} + +void ColladaSerializer::finalize() { + exporter.endDocument(); +} + diff --git a/src/ifcconvert/ColladaSerializer.h b/src/ifcconvert/ColladaSerializer.h new file mode 100644 index 0000000000..1c2aa1e9b2 --- /dev/null +++ b/src/ifcconvert/ColladaSerializer.h @@ -0,0 +1,145 @@ +/******************************************************************************** + * * + * 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 COLLADASERIALIZER_H +#define COLLADASERIALIZER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../ifcgeom/IfcGeomObjects.h" + +#include "../ifcconvert/GeometrySerializer.h" +#include "../ifcconvert/SurfaceStyle.h" + +class ColladaSerializer : public GeometrySerializer +{ +private: + class ColladaExporter + { + private: + class ColladaGeometries : public COLLADASW::LibraryGeometries + { + public: + explicit ColladaGeometries(COLLADASW::StreamWriter& stream) + : COLLADASW::LibraryGeometries(&stream) + {} + void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector& floats, const char* coords = "XYZ"); + void write(const std::string mesh_id, const std::vector& positions, const std::vector& normals, const std::vector& indices); + void close(); + }; + class ColladaScene : public COLLADASW::LibraryVisualScenes + { + private: + const std::string scene_id; + bool scene_opened; + public: + ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream) + : COLLADASW::LibraryVisualScenes(&stream) + , scene_id(scene_id) + , scene_opened(false) + {} + void add(const std::string& node_id, const std::string& node_name, const std::string& geom_id, const std::string& material_id, const std::vector& matrix); + void write(); + }; + class ColladaMaterials : public COLLADASW::LibraryMaterials + { + private: + class ColladaEffects : public COLLADASW::LibraryEffects + { + public: + explicit ColladaEffects(COLLADASW::StreamWriter& stream) + : COLLADASW::LibraryEffects(&stream) + {} + void write(const SurfaceStyle& style); + void close(); + }; + std::vector surface_styles; + ColladaEffects effects; + public: + explicit ColladaMaterials(COLLADASW::StreamWriter& stream) + : COLLADASW::LibraryMaterials(&stream) + , effects(stream) + {} + void add(const SurfaceStyle& style); + bool contains(const std::string& name); + void write(); + }; + class DeferedObject { + public: + const std::string type; + int obj_id; + const std::vector matrix; + const std::vector vertices; + const std::vector normals; + const std::vector indices; + DeferedObject(const std::string& type, int obj_id, const std::vector& matrix, const std::vector& vertices, + const std::vector& normals, const std::vector& indices) + : type(type) + , obj_id(obj_id) + , matrix(matrix) + , vertices(vertices) + , normals(normals) + , indices(indices) + {} + }; + COLLADABU::NativeString filename; + COLLADASW::StreamWriter stream; + ColladaGeometries geometries; + ColladaScene scene; + ColladaMaterials materials; + public: + ColladaExporter(const std::string& scene_name, const std::string& fn) + : filename(fn.c_str()) + , stream(filename) + , geometries(stream) + , scene(scene_name, stream) + , materials(stream) + {} + std::vector deferreds; + virtual ~ColladaExporter() {} + void startDocument(); + void writeTesselated(const std::string& type, int obj_id, const std::vector& matrix, const std::vector& vertices, const std::vector& normals, const std::vector& indices); + void endDocument(); + }; + ColladaExporter exporter; +public: + ColladaSerializer(const std::string& dae_filename) + : GeometrySerializer() + , exporter("IfcOpenShell", dae_filename) + {} + bool ready(); + void writeHeader(); + void writeTesselated(const IfcGeomObjects::IfcGeomObject* o); + void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {} + void finalize(); + bool isTesselated() const { return true; } +}; + +#endif \ No newline at end of file diff --git a/src/ifcconvert/GeometrySerializer.h b/src/ifcconvert/GeometrySerializer.h new file mode 100644 index 0000000000..4524f8b681 --- /dev/null +++ b/src/ifcconvert/GeometrySerializer.h @@ -0,0 +1,36 @@ +/******************************************************************************** + * * + * 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 GEOMETRYSERIALIZER_H +#define GEOMETRYSERIALIZER_H + +#include "../ifcgeom/IfcGeomObjects.h" + +class GeometrySerializer { +public: + virtual bool ready() = 0; + virtual void writeHeader() = 0; + virtual void finalize() = 0; + virtual bool isTesselated() const = 0; + virtual ~GeometrySerializer() {} + virtual void writeTesselated(const IfcGeomObjects::IfcGeomObject* o) = 0; + virtual void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) = 0; +}; + +#endif \ No newline at end of file diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp new file mode 100644 index 0000000000..7ddaa11c3e --- /dev/null +++ b/src/ifcconvert/IfcConvert.cpp @@ -0,0 +1,288 @@ +/******************************************************************************** + * * + * 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 . * + * * + ********************************************************************************/ + +/******************************************************************************** + * * + * This started as a brief example of how IfcOpenShell can be interfaced from * + * within a C++ context, it has since then evolved into a fullfledged command * + * line application that is able to convert geometry in an IFC files into * + * several tesselated and topological output formats. * + * * + ********************************************************************************/ + +#include +#include +#include +#include + +#include + +#include "../ifcgeom/IfcGeomObjects.h" + +#include "../ifcconvert/SurfaceStyle.h" +#include "../ifcconvert/ColladaSerializer.h" +#include "../ifcconvert/IgesSerializer.h" +#include "../ifcconvert/StepSerializer.h" +#include "../ifcconvert/WavefrontObjSerializer.h" + +void printVersion() { + std::cerr << "IfcOpenShell IfcConvert " << IFCOPENSHELL_VERSION << std::endl; +} + +void printUsage(const boost::program_options::options_description& generic_options, const boost::program_options::options_description& geom_options) { + printVersion(); + std::cerr << "Usage: IfcConvert [options] []" << std::endl + << std::endl + << "Converts the geometry in an IFC file into one of the following formats:" << std::endl + << " .obj WaveFront OBJ (a .mtl file is also created)" << std::endl + << " .dae Collada Digital Assets Exchange" << std::endl + << " .stp STEP Standard for the Exchange of Product Data" << std::endl + << " .igs IGES Initial Graphics Exchange Specification" << std::endl + << std::endl + << "Command line options" << std::endl << generic_options << std::endl + << "Advanced options" << std::endl << geom_options << std::endl; +} + +std::string change_extension(const std::string& fn, const std::string& ext) { + std::string::size_type dot = fn.find_last_of('.'); + if (dot != std::string::npos) { + return fn.substr(0,dot+1) + ext; + } else { + return fn + "." + ext; + } +} + +int main(int argc, char** argv) { + boost::program_options::options_description generic_options; + generic_options.add_options() + ("help", "display usage information") + ("version", "display version information") + ("verbose,v", "more verbose output"); + + boost::program_options::options_description fileio_options; + fileio_options.add_options() + ("input-file", boost::program_options::value(), "input IFC file") + ("output-file", boost::program_options::value(), "output geometry file"); + + std::vector ignore_types_vector; + boost::program_options::options_description geom_options; + geom_options.add_options() + ("weld-vertices", "Specifies whether vertices are welded, meaning that the coordinates " + "vector will only contain unique xyz-triplets. This results in a " + "manifold mesh which is useful for modelling applications, but might " + "result in unwanted shading artifacts in rendering applications.") + ("use-world-coords", "Specifies whether to apply the local placements of building elements " + "directly to the coordinates of the representation mesh rather than " + "to represent the local placement in the 4x3 matrix, which will in that " + "case be the identity matrix.") + ("convert-back-units", "Specifies whether to convert back geometrical output back to the " + "unit of measure in which it is defined in the IFC file. Default is " + "to use meters.") + ("sew-shells", "Specifies whether to sew the faces of IfcConnectedFaceSets together. This is a " + "potentially time consuming operation, but guarantees a consistent orientation " + "of surface normals, even if the faces are not properly oriented in the IFC file.") + ("merge-boolean-operands", "Specifies whether to merge all IfcOpening operands into a single" + "operand before applying the subtraction operation. This may " + "introduce a performance improvement at the risk of failing, in " + "which case the subtraction is applied one-by-one.") + ("force-ccw-face-orientation", "Recompute topological face normals using Newell's Method to " + "guarantee that face vertices are defined in a Counter Clock " + "Wise order, even if the faces are not part of a closed shell.") + ("disable-opening-subtractions", "Specifies whether to disable the boolean subtraction of " + "IfcOpeningElement Representations from their RelatingElements.") + ("ignore-types", boost::program_options::value< std::vector >(&ignore_types_vector)->multitoken(), + "A list of IFC datatype keywords that should not be included in the geometrical output"); + + boost::program_options::options_description cmdline_options; + cmdline_options.add(generic_options).add(fileio_options).add(geom_options); + + boost::program_options::positional_options_description positional_options; + positional_options.add("input-file", 1); + positional_options.add("output-file", 1); + + boost::program_options::variables_map vmap; + boost::program_options::store(boost::program_options::command_line_parser(argc, argv). + options(cmdline_options).positional(positional_options).run(), vmap); + boost::program_options::notify(vmap); + + if (vmap.count("help") || !vmap.count("input-file")) { + printUsage(generic_options, geom_options); + return 1; + } else if (vmap.count("version")) { + printVersion(); + return 1; + } + + const bool verbose = vmap.count("verbose") != 0; + const bool weld_vertices = vmap.count("weld-vertices") != 0; + const bool use_world_coords = vmap.count("use-world-coords") != 0; + const bool convert_back_units = vmap.count("convert-back-units") != 0; + const bool sew_shells = vmap.count("sew-shells") != 0; + const bool merge_boolean_operands = vmap.count("merge-boolean-operands") != 0; + const bool force_ccw_face_orientation = vmap.count("force-ccw-face-orientation") != 0; + const bool disable_opening_subtractions = vmap.count("disable-opening-subtractions") != 0; + + // Gets the set ifc types to be ignored from the command line. + std::set ignore_types; + for (std::vector::const_iterator it = ignore_types_vector.begin(); it != ignore_types_vector.end(); ++it) { + std::string lowercase_type = *it; + for (std::string::iterator c = lowercase_type.begin(); c != lowercase_type.end(); ++c) { + *c = tolower(*c); + } + ignore_types.insert(lowercase_type); + } + // If none are specified these are the defaults to skip from output + if (ignore_types_vector.empty()) { + ignore_types.insert("ifcopeningelement"); + ignore_types.insert("ifcspace"); + } + + const std::string input_filename = vmap["input-file"].as(); + // If no output filename is specified a Wavefront OBJ file will be output + // to maintain backwards compatibility with the obsolete IfcObj executable. + const std::string output_filename = vmap.count("output-file") == 1 + ? vmap["output-file"].as() + : change_extension(input_filename, "obj"); + + if (output_filename.size() < 5) { + printUsage(generic_options, geom_options); + return 1; + } + + IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS, use_world_coords); + IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES, weld_vertices); + IfcGeomObjects::Settings(IfcGeomObjects::SEW_SHELLS, sew_shells); + + std::string output_extension = output_filename.substr(output_filename.size()-4); + for (std::string::iterator c = output_extension.begin(); c != output_extension.end(); ++c) { + *c = tolower(*c); + } + + GeometrySerializer* serializer; + if (output_extension == ".obj") { + const std::string mtl_filename = output_filename.substr(0,output_filename.size()-3) + "mtl"; + if (!use_world_coords) { + Logger::Message(Logger::LOG_WARNING, "Use world coord settings ignored for WaveFront OBJ files"); + IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS, true); + } + serializer = new WaveFrontOBJSerializer(output_filename, mtl_filename); + } else if (output_extension == ".dae") { + serializer = new ColladaSerializer(output_filename); + } else if (output_extension == ".stp") { + serializer = new StepSerializer(output_filename); + } else if (output_extension == ".igs") { + // Not sure why this is needed, but it is. + // See: http://tracker.dev.opencascade.org/view.php?id=23679 + IGESControl_Controller::Init(); + serializer = new IgesSerializer(output_filename); + } else { + Logger::Message(Logger::LOG_ERROR, "Unknown output filename extension"); + printUsage(generic_options, geom_options); + return 1; + } + + Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR); + + if (!serializer->ready()) { + Logger::Message(Logger::LOG_ERROR, "Unable to open output file for writing"); + return 1; + } + + serializer->writeHeader(); + + if (!serializer->isTesselated()) { + IfcGeomObjects::Settings(IfcGeomObjects::DISABLE_TRIANGULATION, true); + } + + // Stream for log messages, we don't want to interupt our new progress bar... + std::stringstream ss; + + // Parse the file supplied in argv[1]. Returns true on succes. + if ( ! IfcGeomObjects::Init(input_filename,&std::cout,&ss) ) { + Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file or no geometrical entities found"); + return 1; + } + + std::set materials; + + time_t start,end; + time(&start); + int old_progress = -1; + Logger::Status("Creating geometry..."); + + // The functions IfcGeomObjects::Get() and IfcGeomObjects::Next() wrap an iterator of all geometrical entities in the Ifc file. + // IfcGeomObjects::Get() returns an IfcGeomObjects::IfcGeomObject (see IfcGeomObjects.h for definition) + // IfcGeomObjects::Next() is used to poll whether more geometrical entities are available + do { + const IfcGeomObjects::IfcObject* geom_object; + + if (serializer->isTesselated()) { + geom_object = IfcGeomObjects::Get(); + } else { + geom_object = IfcGeomObjects::GetShapeModel(); + } + + std::string lowercase_type = geom_object->type; + for (std::string::iterator c = lowercase_type.begin(); c != lowercase_type.end(); ++c) { + *c = tolower(*c); + } + if (ignore_types.find(lowercase_type) != ignore_types.end()) continue; + + if (serializer->isTesselated()) { + serializer->writeTesselated(static_cast(geom_object)); + } else { + serializer->writeShapeModel(static_cast(geom_object)); + } + + const int progress = IfcGeomObjects::Progress() / 2; + if ( old_progress!= progress ) Logger::ProgressBar(progress); + old_progress = progress; + + } while ( IfcGeomObjects::Next() ); + + serializer->finalize(); + delete serializer; + + Logger::Status("\rDone creating geometry "); + + // Writes the material settings, defined in Materials.h + std::string log = ss.str(); + if (!log.empty()) { + std::cerr << std::endl << "Log:" << std::endl; + std::cerr << ss.str(); + } + + time(&end); + int dif = (int) difftime (end,start); + printf ("\nConversion took %d seconds\n", dif ); +} + +SurfaceStyle GetDefaultMaterial(const std::string& s) { + if (s == "IfcSite" ) { return SurfaceStyle("IfcSite", 0.75,0.8,0.65); } + if (s == "IfcSlab" ) { return SurfaceStyle("IfcSlab", 0.4, 0.4,0.4 ); } + if (s == "IfcWallStandardCase") { return SurfaceStyle("IfcWallStandardCase",0.9, 0.9,0.9 ); } + if (s == "IfcWall" ) { return SurfaceStyle("IfcWall", 0.9, 0.9,0.9 ); } + if (s == "IfcWindow" ) { return SurfaceStyle("IfcWindow", 0.75,0.8,0.75, 1.0,1.0,1.0, 0.0,0.0,0.0, 500.0, 0.3); } + if (s == "IfcDoor" ) { return SurfaceStyle("IfcDoor", 0.55,0.3,0.15); } + if (s == "IfcBeam" ) { return SurfaceStyle("IfcBeam", 0.75,0.7,0.7 ); } + if (s == "IfcRailing" ) { return SurfaceStyle("IfcRailing", 0.65,0.6,0.6 ); } + if (s == "IfcMember" ) { return SurfaceStyle("IfcMember", 0.65,0.6,0.6 ); } + if (s == "IfcPlate" ) { return SurfaceStyle("IfcPlate", 0.8, 0.8,0.8 ); } + return SurfaceStyle(s); +} diff --git a/src/ifcconvert/IgesSerializer.h b/src/ifcconvert/IgesSerializer.h new file mode 100644 index 0000000000..157fc67759 --- /dev/null +++ b/src/ifcconvert/IgesSerializer.h @@ -0,0 +1,47 @@ +/******************************************************************************** + * * + * 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 IGESSERIALIZER_H +#define IGESSERIALIZER_H + +#include +#include + +#include "../ifcgeom/IfcGeomObjects.h" + +#include "../ifcconvert/OpenCascadeBasedSerializer.h" + +class IgesSerializer : public OpenCascadeBasedSerializer +{ +private: + IGESControl_Writer writer; +public: + explicit IgesSerializer(const std::string& out_filename) + : OpenCascadeBasedSerializer(out_filename) + {} + virtual ~IgesSerializer() {} + void writeShape(const TopoDS_Shape& shape) { + writer.AddShape(shape); + } + void finalize() { + writer.Write(out_filename.c_str()); + } +}; + +#endif \ No newline at end of file diff --git a/src/ifcconvert/OpenCascadeBasedSerializer.cpp b/src/ifcconvert/OpenCascadeBasedSerializer.cpp new file mode 100644 index 0000000000..0b437a2710 --- /dev/null +++ b/src/ifcconvert/OpenCascadeBasedSerializer.cpp @@ -0,0 +1,56 @@ +/******************************************************************************** + * * + * 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 +#include +#include + +#include +#include + +#include "OpenCascadeBasedSerializer.h" + +bool OpenCascadeBasedSerializer::ready() { + std::ofstream test_file(out_filename.c_str(), std::ios_base::binary); + bool succeeded = test_file.is_open(); + test_file.close(); + remove(out_filename.c_str()); + return succeeded; +} + +void OpenCascadeBasedSerializer::writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) { + for (IfcGeom::ShapeList::const_iterator it = o->mesh->begin(); it != o->mesh->end(); ++ it) { + gp_GTrsf gtrsf = *it->first; + gtrsf.PreMultiply(o->trsf); + const TopoDS_Shape& s = *it->second; + + bool trsf_valid = false; + gp_Trsf trsf; + try { + trsf = gtrsf.Trsf(); + trsf_valid = true; + } catch (...) {} + + const TopoDS_Shape moved_shape = trsf_valid + ? BRepBuilderAPI_Transform(s, trsf, true).Shape() + : BRepBuilderAPI_GTransform(s, gtrsf, true).Shape(); + + writeShape(moved_shape); + } +} diff --git a/src/ifcconvert/OpenCascadeBasedSerializer.h b/src/ifcconvert/OpenCascadeBasedSerializer.h new file mode 100644 index 0000000000..2b07ee5a39 --- /dev/null +++ b/src/ifcconvert/OpenCascadeBasedSerializer.h @@ -0,0 +1,46 @@ +/******************************************************************************** + * * + * 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 OPENCASCADEBASEDSERIALIZER_H +#define OPENCASCADEBASEDSERIALIZER_H + +#include "../ifcgeom/IfcGeomObjects.h" + +#include "../ifcconvert/GeometrySerializer.h" +#include "../ifcconvert/SurfaceStyle.h" + +class OpenCascadeBasedSerializer : public GeometrySerializer { +protected: + const std::string& out_filename; +public: + explicit OpenCascadeBasedSerializer(const std::string& out_filename) + : GeometrySerializer() + , out_filename(out_filename) + {} + virtual ~OpenCascadeBasedSerializer() {} + void writeHeader() {} + void writeMaterial(const SurfaceStyle& style) {} + bool ready(); + virtual void writeShape(const TopoDS_Shape& shape) = 0; + void writeTesselated(const IfcGeomObjects::IfcGeomObject* o) {} + void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o); + bool isTesselated() const { return false; } +}; + +#endif \ No newline at end of file diff --git a/src/ifcconvert/StepSerializer.h b/src/ifcconvert/StepSerializer.h new file mode 100644 index 0000000000..db5267af49 --- /dev/null +++ b/src/ifcconvert/StepSerializer.h @@ -0,0 +1,47 @@ +/******************************************************************************** + * * + * 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 STEPSERIALIZER_H +#define STEPSERIALIZER_H + +#include +#include + +#include "../ifcgeom/IfcGeomObjects.h" + +#include "../ifcconvert/OpenCascadeBasedSerializer.h" + +class StepSerializer : public OpenCascadeBasedSerializer +{ +private: + STEPControl_Writer writer; +public: + explicit StepSerializer(const std::string& out_filename) + : OpenCascadeBasedSerializer(out_filename) + {} + virtual ~StepSerializer() {} + void writeShape(const TopoDS_Shape& shape) { + writer.Transfer(shape, STEPControl_AsIs); + } + void finalize() { + writer.Write(out_filename.c_str()); + } +}; + +#endif \ No newline at end of file diff --git a/src/ifcobj/ObjMaterials.h b/src/ifcconvert/SurfaceStyle.h similarity index 51% rename from src/ifcobj/ObjMaterials.h rename to src/ifcconvert/SurfaceStyle.h index e972da6307..87a3e4930d 100644 --- a/src/ifcobj/ObjMaterials.h +++ b/src/ifcconvert/SurfaceStyle.h @@ -19,46 +19,60 @@ /******************************************************************************** * * - * This file defines materials in .mtl format for several IFC datatypes * + * This file defines default materials for several IFC datatypes * * * ********************************************************************************/ +#ifndef SURFACESTYLE_H +#define SURFACESTYLE_H + #include #include -class ObjMaterial { -private: - std::string data; +#include + +class SurfaceStyle { public: - ObjMaterial(const std::string& name, - double Kd_r = 0.7f,double Kd_g = 0.7f,double Kd_b = 0.7f, - double Ks_r = 0.2f,double Ks_g = 0.2f,double Ks_b = 0.2f, - double Ka_r = 0.1f,double Ka_g = 0.1f,double Ka_b = 0.1f, - double Ns = 10.0f, double Tr = 1.0f) { - std::stringstream ss; - ss << "newmtl " << name << std::endl; - ss << "Kd " << Kd_r << " " << Kd_g << " " << Kd_b << std::endl; - ss << "Ks " << Ks_r << " " << Ks_g << " " << Ks_b << std::endl; - ss << "Ka " << Ka_r << " " << Ka_g << " " << Ka_b << std::endl; - ss << "Ns " << Ns << std::endl; - ss << "Tr " << Tr << std::endl; - ss << "d " << Tr << std::endl; - ss << "D " << Tr << std::endl; - data = ss.str(); - } - friend ostream& operator<<(ostream& o, const ObjMaterial& m) {o << m.data; return o;} + class ColorComponent { + private: + std::array data; + public: + ColorComponent(double r, double g, double b) { + data[0] = r; data[1] = g; data[2] = b; + } + const double& R() const { return data[0]; } + const double& G() const { return data[1]; } + const double& B() const { return data[2]; } + double& R() { return data[0]; } + double& G() { return data[1]; } + double& B() { return data[2]; } + }; +private: + std::string name; + ColorComponent diffuse, specular, ambient; + double transparency; + double specularity; +public: + SurfaceStyle(const std::string& name, + double dr = 0.7, double dg = 0.7, double db = 0.7, + double sr = 0.2, double sg = 0.2, double sb = 0.2, + double ar = 0.1, double ag = 0.1, double ab = 0.1, + double Ns = 10.0, double Tr = 1.0) + : name(name) + , diffuse(dr, dg, db) + , specular(sr, sg, sb) + , ambient(ar, ag, ab) + , transparency(Tr) + , specularity(Ns) + {} + const std::string& Name() const { return name; } + const ColorComponent& Diffuse() const { return diffuse; } + const ColorComponent& Specular() const { return specular; } + const ColorComponent& Ambient() const { return ambient; } + double Transparency() const { return transparency; } + double Specularity() const { return specularity; } }; -ObjMaterial GetMaterial(const std::string& s) { - if ( s == "IfcSite" ) { return ObjMaterial("IfcSite",0.75f,0.8f,0.65f); } - if ( s == "IfcSlab" ) { return ObjMaterial("IfcSlab",0.4f,0.4f,0.4f); } - if ( s == "IfcWallStandardCase" ) { return ObjMaterial("IfcWallStandardCase",0.9f,0.9f,0.9f); } - if ( s == "IfcWall" ) { return ObjMaterial("IfcWall",0.9f,0.9f,0.9f); } - if ( s == "IfcWindow" ) { return ObjMaterial("IfcWindow",0.75f,0.8f,0.75f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,500.0f,0.3f); } - if ( s == "IfcDoor" ) { return ObjMaterial("IfcDoor",0.55f,0.3f,0.15f); } - if ( s == "IfcBeam" ) { return ObjMaterial("IfcBeam",0.75f,0.7f,0.7f); } - if ( s == "IfcRailing" ) { return ObjMaterial("IfcRailing",0.65f,0.6f,0.6f); } - if ( s == "IfcMember" ) { return ObjMaterial("IfcMember",0.65f,0.6f,0.6f); } - if ( s == "IfcPlate" ) { return ObjMaterial("IfcPlate",0.8f,0.8f,0.8f); } - return ObjMaterial(s); -} \ No newline at end of file +SurfaceStyle GetDefaultMaterial(const std::string& s); + +#endif \ No newline at end of file diff --git a/src/ifcconvert/WavefrontObjSerializer.cpp b/src/ifcconvert/WavefrontObjSerializer.cpp new file mode 100644 index 0000000000..6882a19049 --- /dev/null +++ b/src/ifcconvert/WavefrontObjSerializer.cpp @@ -0,0 +1,84 @@ +/******************************************************************************** + * * + * 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 "../ifcconvert/SurfaceStyle.h" + +#include "WavefrontOBJSerializer.h" + +bool WaveFrontOBJSerializer::ready() { + return obj_stream.is_open() && mtl_stream.is_open(); +} + +void WaveFrontOBJSerializer::writeHeader() { + obj_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << std::endl; +#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 << std::endl; + mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << std::endl; +} + +void WaveFrontOBJSerializer::writeMaterial(const SurfaceStyle& style) { + mtl_stream << "newmtl " << style.Name() << std::endl + << "Kd " << style.Diffuse().R() << " " << style.Diffuse().G() << " " << style.Diffuse().B() << std::endl + << "Ks " << style.Specular().R() << " " << style.Specular().G() << " " << style.Specular().B() << std::endl + << "Ka " << style.Ambient().R() << " " << style.Ambient().G() << " " << style.Ambient().B() << std::endl + << "Ns " << style.Specularity() << std::endl + << "Tr " << style.Transparency() << std::endl + << "d " << style.Transparency() << std::endl + << "D " << style.Transparency() << std::endl; +} + +void WaveFrontOBJSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject* o) { + const std::string name = o->name.empty() ? o->guid : o->name; + obj_stream << "g " << name << std::endl; + obj_stream << "s 1" << std::endl; + obj_stream << "usemtl " << o->type << std::endl; + if (materials.find(o->type) == materials.end()) { + writeMaterial(GetDefaultMaterial(o->type)); + materials.insert(o->type); + } + const int vcount = o->mesh->verts.size() / 3; + for ( IfcGeomObjects::FltIt it = o->mesh->verts.begin(); it != o->mesh->verts.end(); ) { + const double x = *(it++); + const double y = *(it++); + const double z = *(it++); + obj_stream << "v " << x << " " << y << " " << z << std::endl; + } + for ( IfcGeomObjects::FltIt it = o->mesh->normals.begin(); it != o->mesh->normals.end(); ) { + const double x = *(it++); + const double y = *(it++); + const double z = *(it++); + obj_stream << "vn " << x << " " << y << " " << z << std::endl; + } + for ( IfcGeomObjects::IntIt it = o->mesh->faces.begin(); it != o->mesh->faces.end(); ) { + const int v1 = *(it++)+vcount_total; + const int v2 = *(it++)+vcount_total; + const int v3 = *(it++)+vcount_total; + obj_stream << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << std::endl; + } + vcount_total += vcount; +} diff --git a/src/ifcconvert/WavefrontObjSerializer.h b/src/ifcconvert/WavefrontObjSerializer.h new file mode 100644 index 0000000000..9dd5b9c115 --- /dev/null +++ b/src/ifcconvert/WavefrontObjSerializer.h @@ -0,0 +1,55 @@ +/******************************************************************************** + * * + * 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 WAVEFRONTOBJSERIALIZER_H +#define WAVEFRONTOBJSERIALIZER_H + +#include +#include +#include + +#include "../ifcconvert/GeometrySerializer.h" +#include "../ifcconvert/SurfaceStyle.h" + +class WaveFrontOBJSerializer : public GeometrySerializer { +private: + const std::string mtl_filename; + std::ofstream obj_stream; + std::ofstream mtl_stream; + unsigned int vcount_total; + std::set materials; +public: + WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename) + : GeometrySerializer() + , obj_stream(obj_filename.c_str()) + , mtl_filename(mtl_filename) + , mtl_stream(mtl_filename.c_str()) + , vcount_total(1) + {} + virtual ~WaveFrontOBJSerializer() {} + bool ready(); + void writeHeader(); + void writeMaterial(const SurfaceStyle& style); + void writeTesselated(const IfcGeomObjects::IfcGeomObject* o); + void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {} + void finalize() {} + bool isTesselated() const { return true; } +}; + +#endif \ No newline at end of file diff --git a/src/ifcgeom/IfcGeomObjects.cpp b/src/ifcgeom/IfcGeomObjects.cpp index 0d2f71ec5b..e82158e5be 100644 --- a/src/ifcgeom/IfcGeomObjects.cpp +++ b/src/ifcgeom/IfcGeomObjects.cpp @@ -51,8 +51,9 @@ bool weld_vertices = true; bool convert_back_units = false; bool use_faster_booleans = false; bool disable_subtractions = false; +bool disable_triangulation = false; -int IfcGeomObjects::IfcMesh::addvert(const gp_XYZ& p) { +int IfcGeomObjects::IfcRepresentationTriangulation::addvert(const gp_XYZ& p) { const float X = convert_back_units ? (float) (p.X() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.X(); const float Y = convert_back_units ? (float) (p.Y() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.Y(); const float Z = convert_back_units ? (float) (p.Z() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.Z(); @@ -75,10 +76,10 @@ bool use_brep_data = false; static IfcParse::IfcFile* ifc_file = 0; -IfcGeomObjects::IfcMesh::IfcMesh(int i, const IfcGeom::ShapeList& shapes) { - id = i; - - if ( use_brep_data ) { +IfcGeomObjects::IfcRepresentationBrepData::IfcRepresentationBrepData(const IfcRepresentationShapeModel& shapes) + : id(shapes.getId()) +{ + try { TopoDS_Compound compound; BRep_Builder builder; builder.MakeCompound(compound); @@ -98,18 +99,25 @@ IfcGeomObjects::IfcMesh::IfcMesh(int i, const IfcGeom::ShapeList& shapes) { std::stringstream sstream; BRepTools::Write(compound,sstream); brep_data = sstream.str(); - } else + } catch(...) { + Logger::Message(Logger::LOG_ERROR,"Failed to serialize shape:",ifc_file->EntityById(id)->entity); + } +} + +IfcGeomObjects::IfcRepresentationTriangulation::IfcRepresentationTriangulation(const IfcRepresentationShapeModel& shapes) + : id(shapes.getId()) +{ for ( IfcGeom::ShapeList::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { - const TopoDS_Shape& s = *(*it).second; - const gp_GTrsf& trsf = *(*it).first; + const TopoDS_Shape& s = *it->second; + const gp_GTrsf& trsf = *it->first; // Triangulate the shape try { // BRepTools::Clean(s); BRepMesh::Mesh(s, IfcGeom::GetValue(IfcGeom::GV_DEFLECTION_TOLERANCE)); } catch(...) { - Logger::Message(Logger::LOG_ERROR,"Failed to triangulate mesh:",ifc_file->EntityById(i)->entity); + Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape:",ifc_file->EntityById(id)->entity); continue; } TopExp_Explorer exp; @@ -193,46 +201,62 @@ IfcGeomObjects::IfcMesh::IfcMesh(int i, const IfcGeom::ShapeList& shapes) { } } -IfcGeomObjects::IfcObject::IfcObject(int my_id, - int p_id, - const std::string& n, - const std::string& t, - const std::string& g, - const gp_Trsf& trsf) { - +IfcGeomObjects::IfcObject::IfcObject( + int id, + int parent_id, + const std::string& name, + const std::string& type, + const std::string& guid, + const gp_Trsf& trsf) + : id(id) + , parent_id(parent_id) + , name(name) + , type(type) + , guid(guid) + , trsf(trsf) +{ // Convert the gp_Trsf into a 4x3 Matrix for( int i = 1; i < 5; ++ i ) for ( int j = 1; j < 4; ++ j ) matrix.push_back((float)trsf.Value(j,i)); - - id = my_id; - parent_id = p_id; - name = n; - type = t; - guid = g; } -IfcGeomObjects::IfcGeomObject::IfcGeomObject(int my_id, - int p_id, - const std::string& n, - const std::string& t, - const std::string& g, - const gp_Trsf& trsf, - IfcMesh* m) : IfcObject(my_id,p_id,n,t,g,trsf) { +IfcGeomObjects::IfcGeomShapeModelObject::IfcGeomShapeModelObject( + int id, + int parent_id, + const std::string& name, + const std::string& type, + const std::string& guid, + const gp_Trsf& trsf, + IfcRepresentationShapeModel* shapes) + : IfcObject(id,parent_id,name,type,guid,trsf) + , mesh(shapes) +{} - mesh = m; -} +IfcGeomObjects::IfcGeomBrepDataObject::IfcGeomBrepDataObject( + const IfcGeomShapeModelObject& shape_model) + : IfcObject(shape_model) + , mesh(new IfcRepresentationBrepData(*shape_model.mesh)) +{} + +IfcGeomObjects::IfcGeomObject::IfcGeomObject( + const IfcGeomShapeModelObject& shape_model) + : IfcObject(shape_model) + , mesh(new IfcRepresentationTriangulation(*shape_model.mesh)) +{} // A container and iterator for IfcShapeRepresentations Ifc2x3::IfcShapeRepresentation::list shapereps; -Ifc2x3::IfcShapeRepresentation::it outer; +Ifc2x3::IfcShapeRepresentation::it shaperep_iterator; // The object is fetched beforehand to be positive an entity actually exists -IfcGeomObjects::IfcGeomObject* current_geom_obj; +IfcGeomObjects::IfcGeomObject* current_geom_obj = 0; +IfcGeomObjects::IfcGeomShapeModelObject* current_shape_model_obj = 0; +IfcGeomObjects::IfcGeomBrepDataObject* current_brep_data_obj = 0; -// A container and iterator for IfcBuildingElements for the current IfcShapeRepresentation referenced by *outer +// A container and iterator for IfcBuildingElements for the current IfcShapeRepresentation referenced by *shaperep_iterator Ifc2x3::IfcProduct::list entities; -Ifc2x3::IfcProduct::it inner; +Ifc2x3::IfcProduct::it ifcproduct_iterator; int done; int total; @@ -240,7 +264,7 @@ int total; // Move the the next IfcShapeRepresentation void _nextShape() { entities.reset(); - ++ outer; + ++ shaperep_iterator; ++ done; } @@ -289,17 +313,16 @@ int _getParentId(const Ifc2x3::IfcProduct::ptr ifc_product) { return parent_id; } -// Returns the current IfcGeomObject* -IfcGeomObjects::IfcGeomObject* _get() { +IfcGeomObjects::IfcGeomShapeModelObject* create_shape_model_for_next_entity() { while ( true ) { Ifc2x3::IfcShapeRepresentation::ptr shaperep; // Have we reached the end of our list of representations? - if ( outer == shapereps->end() ) { + if ( shaperep_iterator == shapereps->end() ) { shapereps.reset(); return 0; } - shaperep = *outer; + shaperep = *shaperep_iterator; // Has the list of IfcProducts for this representation been initialized? if ( ! entities ) { @@ -337,15 +360,15 @@ IfcGeomObjects::IfcGeomObject* _get() { _nextShape(); continue; } - inner = entities->begin(); + ifcproduct_iterator = entities->begin(); } // Have we reached the end of our list of IfcProducts? - if ( inner == entities->end() ) { + if ( ifcproduct_iterator == entities->end() ) { _nextShape(); continue; } - IfcGeomObjects::IfcMesh* shape; + IfcGeomObjects::IfcRepresentationShapeModel* shape; IfcGeom::ShapeList shapes; if ( !IfcGeom::convert_shapes(shaperep,shapes) ) { @@ -353,7 +376,7 @@ IfcGeomObjects::IfcGeomObject* _get() { continue; } - Ifc2x3::IfcProduct::ptr ifc_product = *inner; + Ifc2x3::IfcProduct::ptr ifc_product = *ifcproduct_iterator; int parent_id = -1; try { @@ -413,56 +436,74 @@ IfcGeomObjects::IfcGeomObject* _get() { } trsf = gp_Trsf(); } - shape = new IfcGeomObjects::IfcMesh(shaperep->entity->id(),opened_shapes); - for ( IfcGeom::ShapeList::const_iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) { + shape = new IfcGeomObjects::IfcRepresentationShapeModel(shaperep->entity->id(),opened_shapes,true); + for ( IfcGeom::ShapeList::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { delete it->first; - delete it->second; } } else if ( use_world_coords ) { for ( IfcGeom::ShapeList::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { it->first->PreMultiply(trsf); } trsf = gp_Trsf(); - shape = new IfcGeomObjects::IfcMesh(shaperep->entity->id(),shapes); + shape = new IfcGeomObjects::IfcRepresentationShapeModel(shaperep->entity->id(),shapes); } else { - shape = new IfcGeomObjects::IfcMesh(shaperep->entity->id(),shapes); + shape = new IfcGeomObjects::IfcRepresentationShapeModel(shaperep->entity->id(),shapes); } - IfcGeomObjects::IfcGeomObject* geom_obj = new IfcGeomObjects::IfcGeomObject(ifc_product->entity->id(), parent_id, name, + return new IfcGeomObjects::IfcGeomShapeModelObject(ifc_product->entity->id(), parent_id, name, Ifc2x3::Type::ToString(ifc_product->type()), guid, trsf, shape); - - for ( IfcGeom::ShapeList::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { - delete it->first; - } - - return geom_obj; } } -bool IfcGeomObjects::Next() { - if ( current_geom_obj ) { - delete current_geom_obj->mesh; - delete current_geom_obj; - } - if ( entities ) { - ++inner; - } - current_geom_obj = _get(); - if ( ! current_geom_obj ) { +bool try_and_create_representations_for_current_entity() { + current_shape_model_obj = create_shape_model_for_next_entity(); + if (current_shape_model_obj == 0) { return false; - } else { - return true; } + + if (use_brep_data) { + current_brep_data_obj = new IfcGeomObjects::IfcGeomBrepDataObject(*current_shape_model_obj); + if (current_brep_data_obj == 0) { + return false; + } + } + + if (!disable_triangulation) { + current_geom_obj = new IfcGeomObjects::IfcGeomObject(*current_shape_model_obj); + if (current_geom_obj == 0) { + return false; + } + } + + return true; } + +bool IfcGeomObjects::Next() { + // Free all possible representations of the current geometrical entity + delete current_geom_obj; + delete current_brep_data_obj; + delete current_shape_model_obj; + current_geom_obj = 0; + current_brep_data_obj = 0; + current_shape_model_obj = 0; + + // Increment the iterator over the list of products using the current + // shape representation + if (entities) { + ++ifcproduct_iterator; + } + + return try_and_create_representations_for_current_entity(); +} + std::vector returned_objects; bool IfcGeomObjects::CleanUp() { // TODO: Correctly implement destructor for IfcFile delete ifc_file; IfcGeom::Cache::Purge(); - for ( std::vector::const_iterator it = returned_objects.begin(); - it != returned_objects.end(); - ++ it ) { - delete *it; + std::vector::const_iterator it; + for (it = returned_objects.begin(); it != returned_objects.end(); ++ it ) { + delete *it; } returned_objects.clear(); return true; @@ -493,6 +534,12 @@ const IfcGeomObjects::IfcObject* IfcGeomObjects::GetObject(int id) { const IfcGeomObjects::IfcGeomObject* IfcGeomObjects::Get() { return current_geom_obj; } +const IfcGeomObjects::IfcGeomShapeModelObject* IfcGeomObjects::GetShapeModel() { + return current_shape_model_obj; +} +const IfcGeomObjects::IfcGeomBrepDataObject* IfcGeomObjects::GetBrepData() { + return current_brep_data_obj; +} double UnitPrefixToValue( Ifc2x3::IfcSIPrefix::IfcSIPrefix v ) { if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_EXA ) return (double) 1e18; else if ( v == Ifc2x3::IfcSIPrefix::IfcSIPrefix_PETA ) return (double) 1e15; @@ -582,11 +629,12 @@ bool _Init() { shapereps = ifc_file->EntitiesByType(); if ( ! shapereps ) return false; - outer = shapereps->begin(); + shaperep_iterator = shapereps->begin(); entities.reset(); - current_geom_obj = _get(); - - if ( ! current_geom_obj ) return false; + + if (!try_and_create_representations_for_current_entity()) { + return false; + } done = 0; total = shapereps->Size(); @@ -636,6 +684,9 @@ void IfcGeomObjects::Settings(int setting, bool value) { case DISABLE_OPENING_SUBTRACTIONS: disable_subtractions = value; break; + case DISABLE_TRIANGULATION: + disable_triangulation = value; + break; } } int IfcGeomObjects::Progress() { diff --git a/src/ifcgeom/IfcGeomObjects.h b/src/ifcgeom/IfcGeomObjects.h index beb4818092..5e8a1ede2c 100644 --- a/src/ifcgeom/IfcGeomObjects.h +++ b/src/ifcgeom/IfcGeomObjects.h @@ -100,6 +100,10 @@ namespace IfcGeomObjects { // Disables the subtraction of IfcOpeningElement representations from // the related building element representations. const int DISABLE_OPENING_SUBTRACTIONS = 8; + // Disables the triangulation of the topological representations. Useful if + // the client application understands Open Cascade's native format. Note + // that this setting is implied by the USE_BREP_DATA setting. + const int DISABLE_TRIANGULATION = 9; // End of settings enumeration. @@ -111,17 +115,49 @@ namespace IfcGeomObjects { typedef std::map VertKeyMap; typedef std::pair Edge; - class IfcMesh { + class IfcRepresentationShapeModel { + private: + unsigned int id; + bool owns_shapes; + const IfcGeom::ShapeList shapes; + IfcRepresentationShapeModel(const IfcRepresentationShapeModel& other); + IfcRepresentationShapeModel& operator=(const IfcRepresentationShapeModel& other); + public: + IfcRepresentationShapeModel(unsigned int id, const IfcGeom::ShapeList& shapes, bool owns_shapes = false) + : id(id) + , shapes(shapes) + , owns_shapes(owns_shapes) + {} + ~IfcRepresentationShapeModel() { + for ( IfcGeom::ShapeList::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { + delete it->first; + if (owns_shapes) { + delete it->second; + } + } + } + IfcGeom::ShapeList::const_iterator begin() const { return shapes.begin(); } + IfcGeom::ShapeList::const_iterator end() const { return shapes.end(); } + const unsigned int& getId() const { return id; } + }; + + class IfcRepresentationBrepData { + public: + int id; + std::string brep_data; + IfcRepresentationBrepData(const IfcRepresentationShapeModel& s); + }; + + class IfcRepresentationTriangulation { public: int id; std::vector verts; std::vector faces; std::vector edges; std::vector normals; - std::string brep_data; VertKeyMap welds; - IfcMesh(int i, const IfcGeom::ShapeList& s); + IfcRepresentationTriangulation(const IfcRepresentationShapeModel& s); private: int addvert(const gp_XYZ& p); inline void addedge(int n1, int n2, std::map,int>& edgecount, std::vector >& edges_temp) { @@ -129,7 +165,7 @@ namespace IfcGeomObjects { if ( edgecount.find(e) == edgecount.end() ) edgecount[e] = 1; else edgecount[e] ++; edges_temp.push_back(e); - } + } }; class IfcObject { @@ -140,28 +176,68 @@ namespace IfcGeomObjects { std::string type; std::string guid; std::vector matrix; - IfcObject(int my_id, int p_id, const std::string& n, const std::string& t, const std::string& g, const gp_Trsf& trsf); + gp_Trsf trsf; + IfcObject(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf); + virtual ~IfcObject() {} + }; + + class IfcGeomShapeModelObject : public IfcObject { + public: + IfcRepresentationShapeModel* mesh; + IfcGeomShapeModelObject(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf, IfcRepresentationShapeModel* mesh); + virtual ~IfcGeomShapeModelObject() { + delete mesh; + } + private: + IfcGeomShapeModelObject(const IfcGeomShapeModelObject& other); + IfcGeomShapeModelObject& operator=(const IfcGeomShapeModelObject& other); + }; class IfcGeomObject : public IfcObject { public: - IfcMesh* mesh; - IfcGeomObject(int my_id, int p_id, const std::string& n, const std::string& t, const std::string& g, const gp_Trsf& trsf, IfcMesh* m); + IfcRepresentationTriangulation* mesh; + IfcGeomObject(const IfcGeomShapeModelObject& shape_model); + virtual ~IfcGeomObject() { + delete mesh; + } + private: + IfcGeomObject(const IfcGeomObject& other); + IfcGeomObject& operator=(const IfcGeomObject& other); + }; + + class IfcGeomBrepDataObject : public IfcObject { + public: + IfcRepresentationBrepData* mesh; + IfcGeomBrepDataObject(const IfcGeomShapeModelObject& shape_model); + virtual ~IfcGeomBrepDataObject() { + delete mesh; + } + private: + IfcGeomBrepDataObject(const IfcGeomBrepDataObject& other); + IfcGeomBrepDataObject& operator=(const IfcGeomBrepDataObject& other); }; - void InitUnits(); bool Init(const std::string fn); bool Init(void* data, int len); bool Init(const std::string fn, std::ostream* log1= 0, std::ostream* log2= 0); bool Init(std::istream& f, int len, std::ostream* log1= 0, std::ostream* log2= 0); + void Settings(int setting, bool value); - bool CleanUp(); + void InitUnits(); + const IfcGeomObject* Get(); - bool Next(); - int Progress(); const IfcObject* GetObject(int id); + const IfcGeomBrepDataObject* GetBrepData(); + const IfcGeomShapeModelObject* GetShapeModel(); + + bool Next(); + int Progress(); + std::string GetLog(); - IfcParse::IfcFile* GetFile(); + IfcParse::IfcFile* GetFile(); + + bool CleanUp(); } #endif diff --git a/src/ifcobj/IfcObj.cpp b/src/ifcobj/IfcObj.cpp deleted file mode 100644 index 6ec3ddd1d2..0000000000 --- a/src/ifcobj/IfcObj.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/******************************************************************************** - * * - * 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 . * - * * - ********************************************************************************/ - -/******************************************************************************** - * * - * This is a brief example of how IfcOpenShell can be interfaced from within * - * a C++ context. The application reads an .ifc file and outputs geometry in * - * the Wavefront .obj file format. * - * * - ********************************************************************************/ - -#include -#include -#include -#include - -#include "../ifcgeom/IfcGeomObjects.h" -#include "../ifcobj/ObjMaterials.h" - -int main ( int argc, char** argv ) { - if ( argc != 2 ) { - std::cout << "usage: IfcObj " << std::endl; - return 1; - } - const std::string fnObj = std::string(argv[1]) + ".obj"; - const std::string fnMtl = std::string(argv[1]) + ".mtl"; - ofstream fObj(fnObj.c_str()); - ofstream fMtl(fnMtl.c_str()); - if ( ! ( fObj.is_open() && fMtl.is_open() ) ) { - std::cout << "[Error] unable to open output file for writing" << std::endl; - return 1; - } - - IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS,true); - IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES,false); - IfcGeomObjects::Settings(IfcGeomObjects::SEW_SHELLS,true); - - // Stream for log messages, we don't want to interupt our new progress bar... - std::stringstream ss; - - // Parse the file supplied in argv[1]. Returns true on succes. - if ( ! IfcGeomObjects::Init(argv[1],&std::cout,&ss) ) { - std::cout << "[Error] unable to parse .ifc file or no geometrical entities found" << std::endl; - return 1; - } - - fObj << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << std::endl; - fObj << "mtllib " << fnMtl << std::endl; - std::set materials; - - time_t start,end; - time(&start); - int old_progress = -1; - std::cout << "Creating geometry..." << std::endl; - - // The functions IfcGeomObjects::Get() and IfcGeomObjects::Next() wrap an iterator of all geometrical entities in the Ifc file. - // IfcGeomObjects::Get() returns an IfcGeomObjects::IfcGeomObject (see IfcGeomObjects.h for definition) - // IfcGeomObjects::Next() is used to poll whether more geometrical entities are available - int vcount_total = 1; - do { - const IfcGeomObjects::IfcGeomObject* o = IfcGeomObjects::Get(); - if ( o->type == "IfcSpace" || o->type == "IfcOpeningElement" ) continue; - const std::string name = o->name.empty() ? o->guid : o->name; - fObj << "g " << name << std::endl; - fObj << "s 1" << std::endl; - fObj << "usemtl " << o->type << std::endl; - materials.insert(o->type); - const int vcount = o->mesh->verts.size() / 3; - for ( IfcGeomObjects::FltIt it = o->mesh->verts.begin(); it != o->mesh->verts.end(); ) { - const double x = *(it++); - const double y = *(it++); - const double z = *(it++); - fObj << "v " << x << " " << y << " " << z << std::endl; - } - for ( IfcGeomObjects::FltIt it = o->mesh->normals.begin(); it != o->mesh->normals.end(); ) { - const double x = *(it++); - const double y = *(it++); - const double z = *(it++); - fObj << "vn " << x << " " << y << " " << z << std::endl; - } - for ( IfcGeomObjects::IntIt it = o->mesh->faces.begin(); it != o->mesh->faces.end(); ) { - const int v1 = *(it++)+vcount_total; - const int v2 = *(it++)+vcount_total; - const int v3 = *(it++)+vcount_total; - fObj << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << std::endl; - } - vcount_total += vcount; - - const int progress = IfcGeomObjects::Progress() / 2; - if ( old_progress!= progress ) std::cout << "\r[" << std::string(progress,'#') << std::string(50 - progress,' ') << "]" << std::flush; - old_progress = progress; - - } while ( IfcGeomObjects::Next() ); - std::cout << "\rDone creating geometry " << std::endl; - - // Writes the material settings, defined in Materials.h - fMtl << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << std::endl; - for( std::set::iterator it = materials.begin(); it != materials.end(); ++ it ) { - fMtl << GetMaterial(*it); - } - - std::string log = ss.str(); - if ( log.size() ) { - std::cout << std::endl << "Log:" << std::endl; - std::cout << ss.str(); - } - - time(&end); - int dif = (int) difftime (end,start); - printf ("\nConversion took %d seconds\n", dif ); -} diff --git a/src/ifcobj/Materials.cpp b/src/ifcobj/Materials.cpp deleted file mode 100644 index f27c475e04..0000000000 --- a/src/ifcobj/Materials.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "../IfcObj/Materials.h" - -void InitMaterials() { - materials["IFCSITE"] = ObjMaterial("IFCSITE",0.7f,0.8f,0.5f); -} \ No newline at end of file diff --git a/src/ifcparse/IfcUtil.cpp b/src/ifcparse/IfcUtil.cpp index 04cc19fab3..0a85980bb5 100644 --- a/src/ifcparse/IfcUtil.cpp +++ b/src/ifcparse/IfcUtil.cpp @@ -83,6 +83,11 @@ void Logger::Status(const std::string& message, bool new_line) { else (*log1) << std::flush; } } +void Logger::ProgressBar(int progress) { + if ( log1 ) { + Status("\r[" + std::string(progress,'#') + std::string(50 - progress,' ') + "]", false); + } +} std::string Logger::GetLog() { return log_stream.str(); } diff --git a/src/ifcparse/IfcUtil.h b/src/ifcparse/IfcUtil.h index 21451fb058..03ce7a754d 100644 --- a/src/ifcparse/IfcUtil.h +++ b/src/ifcparse/IfcUtil.h @@ -212,6 +212,7 @@ public: /// Log a message to the output stream static void Message(Severity type, const std::string& message, const IfcAbstractEntityPtr entity=0); static void Status(const std::string& message, bool new_line=true); + static void ProgressBar(int progress); static std::string GetLog(); }; diff --git a/win/IfcObj.vcproj b/win/IfcConvert.vcproj similarity index 75% rename from win/IfcObj.vcproj rename to win/IfcConvert.vcproj index b7093b850d..bc7733ed4f 100644 --- a/win/IfcObj.vcproj +++ b/win/IfcConvert.vcproj @@ -2,9 +2,9 @@ @@ -60,7 +60,7 @@ /> @@ -130,7 +130,7 @@ /> + + + + + + @@ -178,7 +190,31 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + + + + + + + + + + + diff --git a/win/IfcOpenShell.sln b/win/IfcOpenShell.sln index b21e1471d7..898dddbb71 100644 --- a/win/IfcOpenShell.sln +++ b/win/IfcOpenShell.sln @@ -13,7 +13,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IfcMax", "IfcMax.vcproj", " {F7600775-3D48-426A-88E2-F3A4BF4408A2} = {F7600775-3D48-426A-88E2-F3A4BF4408A2} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IfcObj", "IfcObj.vcproj", "{5B0BAAB3-9FC4-4C0C-9D38-8BF4B07F4A85}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IfcConvert", "IfcConvert.vcproj", "{5B0BAAB3-9FC4-4C0C-9D38-8BF4B07F4A85}" ProjectSection(ProjectDependencies) = postProject {BA57AF0F-1D12-4FAC-BD40-7474D729CAE9} = {BA57AF0F-1D12-4FAC-BD40-7474D729CAE9} {F7600775-3D48-426A-88E2-F3A4BF4408A2} = {F7600775-3D48-426A-88E2-F3A4BF4408A2}