First push of a more all-round geometrical file conversion utility

This commit is contained in:
Thomas Krijnen
2013-03-24 10:48:39 +00:00
parent 852cb7d8c4
commit 5d4ff0b54a
20 changed files with 1330 additions and 264 deletions
+206
View File
@@ -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();
}
+145
View File
@@ -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
+36
View File
@@ -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
+288
View File
@@ -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);
}
+47
View File
@@ -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
+47
View File
@@ -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
+78
View File
@@ -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
+84
View File
@@ -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;
}
+55
View File
@@ -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