mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-07 12:56:26 +00:00
First push of a more all-round geometrical file conversion utility
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1,78 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 file defines default materials for several IFC datatypes *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef SURFACESTYLE_H
|
||||
#define SURFACESTYLE_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <array>
|
||||
|
||||
class SurfaceStyle {
|
||||
public:
|
||||
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; }
|
||||
};
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user