mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-05 23:41:44 +00:00
First push of a more all-round geometrical file conversion utility
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "ColladaSerializer.h"
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<float>& 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<float>::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<float>& positions, const std::vector<float>& normals, const std::vector<int>& 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<float>& 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<float>& matrix, const std::vector<float>& vertices, const std::vector<float>& normals, const std::vector<int>& 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();
|
||||
}
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef COLLADASERIALIZER_H
|
||||
#define COLLADASERIALIZER_H
|
||||
|
||||
#include <COLLADASWStreamWriter.h>
|
||||
#include <COLLADASWPrimitves.h>
|
||||
#include <COLLADASWLibraryGeometries.h>
|
||||
#include <COLLADASWSource.h>
|
||||
#include <COLLADASWScene.h>
|
||||
#include <COLLADASWNode.h>
|
||||
#include <COLLADASWInstanceGeometry.h>
|
||||
#include <COLLADASWLibraryVisualScenes.h>
|
||||
#include <COLLADASWLibraryEffects.h>
|
||||
#include <COLLADASWLibraryMaterials.h>
|
||||
#include <COLLADASWBaseInputElement.h>
|
||||
#include <COLLADASWAsset.h>
|
||||
|
||||
#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<float>& floats, const char* coords = "XYZ");
|
||||
void write(const std::string mesh_id, const std::vector<float>& positions, const std::vector<float>& normals, const std::vector<int>& 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<float>& 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<SurfaceStyle> 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<float> matrix;
|
||||
const std::vector<float> vertices;
|
||||
const std::vector<float> normals;
|
||||
const std::vector<int> indices;
|
||||
DeferedObject(const std::string& type, int obj_id, const std::vector<float>& matrix, const std::vector<float>& vertices,
|
||||
const std::vector<float>& normals, const std::vector<int>& 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<DeferedObject> deferreds;
|
||||
virtual ~ColladaExporter() {}
|
||||
void startDocument();
|
||||
void writeTesselated(const std::string& type, int obj_id, const std::vector<float>& matrix, const std::vector<float>& vertices, const std::vector<float>& normals, const std::vector<int>& 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
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 <fstream>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <time.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#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] <input.ifc> [<output>]" << 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<std::string>(), "input IFC file")
|
||||
("output-file", boost::program_options::value<std::string>(), "output geometry file");
|
||||
|
||||
std::vector<std::string> 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<std::string> >(&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<std::string> ignore_types;
|
||||
for (std::vector<std::string>::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<std::string>();
|
||||
// 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<std::string>()
|
||||
: 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<std::string> 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<const IfcGeomObjects::IfcGeomObject*>(geom_object));
|
||||
} else {
|
||||
serializer->writeShapeModel(static_cast<const IfcGeomObjects::IfcGeomShapeModelObject*>(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);
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IGESSERIALIZER_H
|
||||
#define IGESSERIALIZER_H
|
||||
|
||||
#include <IGESControl_Controller.hxx>
|
||||
#include <IGESControl_Writer.hxx>
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
|
||||
#include <BRepBuilderAPI_GTransform.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef STEPSERIALIZER_H
|
||||
#define STEPSERIALIZER_H
|
||||
|
||||
#include <STEPControl_Controller.hxx>
|
||||
#include <STEPControl_Writer.hxx>
|
||||
|
||||
#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
|
||||
@@ -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 <string>
|
||||
#include <sstream>
|
||||
|
||||
class ObjMaterial {
|
||||
private:
|
||||
std::string data;
|
||||
#include <array>
|
||||
|
||||
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<double, 3> 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);
|
||||
}
|
||||
SurfaceStyle GetDefaultMaterial(const std::string& s);
|
||||
|
||||
#endif
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef WAVEFRONTOBJSERIALIZER_H
|
||||
#define WAVEFRONTOBJSERIALIZER_H
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#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<std::string> 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
|
||||
+127
-76
@@ -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<IfcGeomObjects::IfcObject*> returned_objects;
|
||||
bool IfcGeomObjects::CleanUp() {
|
||||
// TODO: Correctly implement destructor for IfcFile
|
||||
delete ifc_file;
|
||||
IfcGeom::Cache::Purge();
|
||||
for ( std::vector<IfcGeomObjects::IfcObject*>::const_iterator it = returned_objects.begin();
|
||||
it != returned_objects.end();
|
||||
++ it ) {
|
||||
delete *it;
|
||||
std::vector<IfcGeomObjects::IfcObject*>::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<Ifc2x3::IfcShapeRepresentation>();
|
||||
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() {
|
||||
|
||||
@@ -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<VertKey,int> VertKeyMap;
|
||||
typedef std::pair<int,int> 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<float> verts;
|
||||
std::vector<int> faces;
|
||||
std::vector<int> edges;
|
||||
std::vector<float> 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<std::pair<int,int>,int>& edgecount, std::vector<std::pair<int,int> >& 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<float> 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
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 <fstream>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <time.h>
|
||||
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
#include "../ifcobj/ObjMaterials.h"
|
||||
|
||||
int main ( int argc, char** argv ) {
|
||||
if ( argc != 2 ) {
|
||||
std::cout << "usage: IfcObj <filename.ifc>" << 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<std::string> 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<std::string>::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 );
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#include "../IfcObj/Materials.h"
|
||||
|
||||
void InitMaterials() {
|
||||
materials["IFCSITE"] = ObjMaterial("IFCSITE",0.7f,0.8f,0.5f);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="IfcObj"
|
||||
Name="IfcConvert"
|
||||
ProjectGUID="{5B0BAAB3-9FC4-4C0C-9D38-8BF4B07F4A85}"
|
||||
RootNamespace="IfcObj"
|
||||
RootNamespace="IfcConvert"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
@@ -60,7 +60,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="TKerneld.lib TKMathd.lib TKBRepd.lib TKGeomBased.lib TKGeomAlgod.lib TKG3dd.lib TKG2dd.lib TKShHealingd.lib TKTopAlgod.lib TKMeshd.lib TKPrimd.lib TKBoold.lib TKBOd.lib TKFilletd.lib"
|
||||
AdditionalDependencies="TKerneld.lib TKMathd.lib TKBRepd.lib TKGeomBased.lib TKGeomAlgod.lib TKG3dd.lib TKG2dd.lib TKShHealingd.lib TKTopAlgod.lib TKMeshd.lib TKPrimd.lib TKBoold.lib TKBOd.lib TKFilletd.lib TKSTEPd.lib TKSTEPBased.lib TKSTEPAttrd.lib TKXSBased.lib TKSTEP209d.lib TKIGESd.lib"
|
||||
GenerateDebugInformation="true"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
@@ -130,7 +130,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="TKernel.lib TKMath.lib TKBRep.lib TKGeomBase.lib TKGeomAlgo.lib TKG3d.lib TKG2d.lib TKShHealing.lib TKTopAlgo.lib TKMesh.lib TKPrim.lib TKBool.lib TKBO.lib TKFillet.lib"
|
||||
AdditionalDependencies="TKernel.lib TKMath.lib TKBRep.lib TKGeomBase.lib TKGeomAlgo.lib TKG3d.lib TKG2d.lib TKShHealing.lib TKTopAlgo.lib TKMesh.lib TKPrim.lib TKBool.lib TKBO.lib TKFillet.lib TKSTEP.lib TKSTEPBase.lib TKSTEPAttr.lib TKXSBase.lib TKSTEP209.lib TKIGES.lib"
|
||||
GenerateDebugInformation="true"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
@@ -168,7 +168,19 @@
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\src\ifcobj\IfcObj.cpp"
|
||||
RelativePath="..\src\ifcconvert\ColladaSerializer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ifcconvert\IfcConvert.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ifcconvert\OpenCascadeBasedSerializer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ifcconvert\WavefrontObjSerializer.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
@@ -178,7 +190,31 @@
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\src\ifcobj\ObjMaterials.h"
|
||||
RelativePath="..\src\ifcconvert\ColladaSerializer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ifcconvert\GeometrySerializer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ifcconvert\IgesSerializer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ifcconvert\OpenCascadeBasedSerializer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ifcconvert\StepSerializer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ifcconvert\SurfaceStyle.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ifcconvert\WavefrontObjSerializer.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user