2013-03-24 10:48:39 +00:00
|
|
|
/********************************************************************************
|
|
|
|
|
* *
|
|
|
|
|
* 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/>. *
|
|
|
|
|
* *
|
|
|
|
|
********************************************************************************/
|
|
|
|
|
|
2013-11-22 08:23:11 +00:00
|
|
|
#ifdef WITH_OPENCOLLADA
|
|
|
|
|
|
2013-03-24 10:48:39 +00:00
|
|
|
#include "ColladaSerializer.h"
|
|
|
|
|
|
2016-03-10 11:35:32 +02:00
|
|
|
#include <COLLADASWPrimitves.h>
|
|
|
|
|
#include <COLLADASWSource.h>
|
|
|
|
|
#include <COLLADASWScene.h>
|
|
|
|
|
#include <COLLADASWNode.h>
|
|
|
|
|
#include <COLLADASWInstanceGeometry.h>
|
|
|
|
|
#include <COLLADASWBaseInputElement.h>
|
|
|
|
|
#include <COLLADASWAsset.h>
|
|
|
|
|
|
2016-03-18 11:23:25 +01:00
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
|
|
|
|
|
|
#include <string>
|
2016-03-10 11:35:32 +02:00
|
|
|
#include <cmath>
|
2016-03-18 11:23:25 +01:00
|
|
|
|
2017-04-11 17:26:30 +02:00
|
|
|
using namespace IfcSchema;
|
|
|
|
|
|
2016-03-10 11:35:32 +02:00
|
|
|
static void collada_id(std::string &s)
|
|
|
|
|
{
|
|
|
|
|
IfcUtil::sanitate_material_name(s);
|
|
|
|
|
IfcUtil::escape_xml(s);
|
2013-05-05 08:49:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-03-10 11:35:32 +02:00
|
|
|
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id,
|
|
|
|
|
const std::string& suffix, const std::vector<real_t>& floats, const char* coords /* = "XYZ" */)
|
|
|
|
|
{
|
2013-03-24 10:48:39 +00:00
|
|
|
COLLADASW::FloatSource source(mSW);
|
|
|
|
|
source.setId(mesh_id + suffix);
|
|
|
|
|
source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX);
|
2016-03-10 11:35:32 +02:00
|
|
|
const size_t num_elems = strlen(coords);
|
|
|
|
|
source.setAccessorStride(static_cast<unsigned long>(num_elems));
|
|
|
|
|
source.setAccessorCount(static_cast<unsigned long>(floats.size() / num_elems));
|
|
|
|
|
for (size_t i = 0; i < num_elems; ++i) {
|
2013-03-24 10:48:39 +00:00
|
|
|
source.getParameterNameList().push_back(std::string(1, coords[i]));
|
|
|
|
|
}
|
|
|
|
|
source.prepareToAppendValues();
|
2016-03-10 11:35:32 +02:00
|
|
|
for (std::vector<real_t>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
|
2013-03-24 10:48:39 +00:00
|
|
|
source.appendValues(*it);
|
|
|
|
|
}
|
|
|
|
|
source.finish();
|
|
|
|
|
}
|
2016-03-10 11:35:32 +02:00
|
|
|
|
|
|
|
|
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(
|
|
|
|
|
const std::string &mesh_id, const std::string& default_material_name, const std::vector<real_t>& positions,
|
|
|
|
|
const std::vector<real_t>& normals, const std::vector<int>& faces, const std::vector<int>& edges,
|
2016-03-17 00:25:33 +02:00
|
|
|
const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials,
|
|
|
|
|
const std::vector<real_t>& uvs)
|
2016-03-10 11:35:32 +02:00
|
|
|
{
|
2013-03-24 10:48:39 +00:00
|
|
|
openMesh(mesh_id);
|
2017-04-11 17:26:30 +02:00
|
|
|
|
2013-05-05 08:49:25 +00:00
|
|
|
// 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.
|
|
|
|
|
const bool has_normals = !normals.empty();
|
2016-03-17 00:25:33 +02:00
|
|
|
const bool has_uvs = !uvs.empty();
|
2017-04-11 17:26:30 +02:00
|
|
|
|
2013-03-24 10:48:39 +00:00
|
|
|
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX, positions);
|
2013-05-05 08:49:25 +00:00
|
|
|
if (has_normals) {
|
2013-03-24 10:48:39 +00:00
|
|
|
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, normals);
|
2016-03-17 00:25:33 +02:00
|
|
|
if (has_uvs) {
|
|
|
|
|
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::TEXCOORDS_SOURCE_ID_SUFFIX, uvs, "UV");
|
2016-03-10 11:35:32 +02:00
|
|
|
}
|
2013-03-24 10:48:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
2015-04-22 09:15:48 +00:00
|
|
|
std::vector<int>::const_iterator index_range_start = faces.begin();
|
2013-05-05 08:49:25 +00:00
|
|
|
std::vector<int>::const_iterator material_it = material_ids.begin();
|
2014-12-19 12:14:36 +00:00
|
|
|
int previous_material_id = -1;
|
2015-04-22 09:15:48 +00:00
|
|
|
for (std::vector<int>::const_iterator it = faces.begin(); !faces.empty(); it += 3) {
|
2016-03-18 11:18:02 +01:00
|
|
|
|
|
|
|
|
int current_material_id = 0;
|
|
|
|
|
if (material_it != material_ids.end()) {
|
|
|
|
|
// In order for the last range of equal material ids to be output as well, this loop iterates
|
|
|
|
|
// one element past the end of the vector. This needs to be observed when incrementing.
|
|
|
|
|
current_material_id = *(material_it++);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-22 16:15:28 +01:00
|
|
|
const size_t num_triangles = std::distance(index_range_start, it) / 3;
|
2015-04-22 09:15:48 +00:00
|
|
|
if ((previous_material_id != current_material_id && num_triangles > 0) || (it == faces.end())) {
|
2013-05-05 08:49:25 +00:00
|
|
|
COLLADASW::Triangles triangles(mSW);
|
2017-01-11 12:00:51 +02:00
|
|
|
std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES)
|
2016-03-10 12:01:04 +02:00
|
|
|
? materials[previous_material_id].original_name() : materials[previous_material_id].name());
|
2016-03-10 11:35:32 +02:00
|
|
|
collada_id(material_name);
|
|
|
|
|
triangles.setMaterial(material_name);
|
|
|
|
|
triangles.setCount((unsigned long)num_triangles);
|
2013-05-05 08:49:25 +00:00
|
|
|
int offset = 0;
|
2016-03-10 11:35:32 +02:00
|
|
|
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++));
|
2013-05-05 08:49:25 +00:00
|
|
|
if (has_normals) {
|
2016-03-10 11:35:32 +02:00
|
|
|
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++));
|
2013-05-05 08:49:25 +00:00
|
|
|
}
|
2016-03-17 00:25:33 +02:00
|
|
|
if (has_uvs) {
|
2016-03-10 11:35:32 +02:00
|
|
|
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::TEXCOORD,"#" + mesh_id + COLLADASW::LibraryGeometries::TEXCOORDS_SOURCE_ID_SUFFIX, offset++));
|
|
|
|
|
}
|
2013-05-05 08:49:25 +00:00
|
|
|
triangles.prepareToAppendValues();
|
|
|
|
|
for (std::vector<int>::const_iterator jt = index_range_start; jt != it; ++jt) {
|
|
|
|
|
const int idx = *jt;
|
2016-03-17 00:25:33 +02:00
|
|
|
if (has_normals && has_uvs) {
|
2016-03-10 11:35:32 +02:00
|
|
|
triangles.appendValues(idx, idx, idx);
|
2016-03-10 16:46:20 +02:00
|
|
|
} else if(has_normals) {
|
2013-05-05 08:49:25 +00:00
|
|
|
triangles.appendValues(idx, idx);
|
|
|
|
|
} else {
|
|
|
|
|
triangles.appendValues(idx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
triangles.finish();
|
|
|
|
|
index_range_start = it;
|
|
|
|
|
}
|
|
|
|
|
previous_material_id = current_material_id;
|
2015-04-22 09:15:48 +00:00
|
|
|
if (it == faces.end()) {
|
2013-05-05 08:49:25 +00:00
|
|
|
break;
|
2013-03-24 10:48:39 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-22 09:15:48 +00:00
|
|
|
std::set<int> faces_set (faces.begin(), faces.end());
|
|
|
|
|
typedef std::vector< std::pair<int, std::vector<unsigned long> > > linelist_t;
|
|
|
|
|
linelist_t linelist;
|
|
|
|
|
|
|
|
|
|
int num_lines = 0;
|
|
|
|
|
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ++num_lines) {
|
|
|
|
|
const int i1 = *(it++);
|
|
|
|
|
const int i2 = *(it++);
|
|
|
|
|
|
|
|
|
|
if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int current_material_id = *(material_it++);
|
|
|
|
|
if ((previous_material_id != current_material_id) || (num_lines == 0)) {
|
|
|
|
|
linelist.resize(linelist.size() + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
linelist.rbegin()->second.push_back(i1);
|
|
|
|
|
linelist.rbegin()->second.push_back(i2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (linelist_t::const_iterator it = linelist.begin(); it != linelist.end(); ++it) {
|
|
|
|
|
COLLADASW::Lines lines(mSW);
|
2017-01-11 12:00:51 +02:00
|
|
|
std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES)
|
2016-03-10 12:01:04 +02:00
|
|
|
? materials[it->first].original_name() : materials[it->first].name());
|
2016-03-10 11:35:32 +02:00
|
|
|
collada_id(material_name);
|
|
|
|
|
lines.setMaterial(material_name);
|
2015-11-03 17:58:08 +02:00
|
|
|
lines.setCount((unsigned long)it->second.size());
|
2015-04-22 09:15:48 +00:00
|
|
|
int offset = 0;
|
2016-03-10 11:35:32 +02:00
|
|
|
lines.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX, "#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset));
|
2015-04-22 09:15:48 +00:00
|
|
|
lines.prepareToAppendValues();
|
|
|
|
|
lines.appendValues(it->second);
|
|
|
|
|
lines.finish();
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-24 10:48:39 +00:00
|
|
|
closeMesh();
|
|
|
|
|
closeGeometry();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColladaSerializer::ColladaExporter::ColladaGeometries::close() {
|
|
|
|
|
closeLibrary();
|
|
|
|
|
}
|
2016-03-10 11:35:32 +02:00
|
|
|
|
|
|
|
|
void ColladaSerializer::ColladaExporter::ColladaScene::add(
|
|
|
|
|
const std::string& node_id, const std::string& node_name, const std::string& geom_name,
|
|
|
|
|
const std::vector<std::string>& material_ids, const std::vector<real_t>& matrix)
|
|
|
|
|
{
|
2013-03-24 10:48:39 +00:00
|
|
|
if (!scene_opened) {
|
|
|
|
|
openVisualScene(scene_id);
|
|
|
|
|
scene_opened = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COLLADASW::Node node(mSW);
|
|
|
|
|
node.setNodeId(node_id);
|
|
|
|
|
node.setNodeName(node_name);
|
2013-05-05 08:49:25 +00:00
|
|
|
node.setType(COLLADASW::Node::NODE);
|
2013-03-24 10:48:39 +00:00
|
|
|
|
|
|
|
|
// 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] = {
|
2016-03-10 11:35:32 +02:00
|
|
|
{ (double)matrix[0], (double)matrix[3], (double)matrix[6], (double)matrix[ 9] },
|
|
|
|
|
{ (double)matrix[1], (double)matrix[4], (double)matrix[7], (double)matrix[10] },
|
|
|
|
|
{ (double)matrix[2], (double)matrix[5], (double)matrix[8], (double)matrix[11] },
|
|
|
|
|
{ 0, 0, 0, 1 }
|
2013-03-24 10:48:39 +00:00
|
|
|
};
|
|
|
|
|
|
2016-03-10 11:35:32 +02:00
|
|
|
matrix_array[0][3] += serializer->settings().offset[0];
|
|
|
|
|
matrix_array[1][3] += serializer->settings().offset[1];
|
|
|
|
|
matrix_array[2][3] += serializer->settings().offset[2];
|
|
|
|
|
|
2013-03-24 10:48:39 +00:00
|
|
|
node.start();
|
|
|
|
|
node.addMatrix(matrix_array);
|
|
|
|
|
COLLADASW::InstanceGeometry instanceGeometry(mSW);
|
2013-05-05 08:49:25 +00:00
|
|
|
instanceGeometry.setUrl ("#" + geom_name);
|
2016-03-10 11:35:32 +02:00
|
|
|
foreach(std::string material_name, material_ids) {
|
|
|
|
|
/// @todo This is done 6 times in this file, try to perform this once and be done with the material naming for the export.
|
|
|
|
|
collada_id(material_name);
|
|
|
|
|
COLLADASW::InstanceMaterial material (material_name, "#" + material_name);
|
2013-05-05 08:49:25 +00:00
|
|
|
instanceGeometry.getBindMaterial().getInstanceMaterialList().push_back(material);
|
|
|
|
|
}
|
2013-03-24 10:48:39 +00:00
|
|
|
instanceGeometry.add();
|
|
|
|
|
node.end();
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-19 11:48:52 +02:00
|
|
|
void ColladaSerializer::ColladaExporter::ColladaScene::addParent(const IfcGeom::Element<real_t>& parent){
|
2017-04-21 16:15:41 +02:00
|
|
|
//we open the visual scene tag if it's not.
|
2017-04-13 16:39:36 +02:00
|
|
|
if (!scene_opened) {
|
|
|
|
|
openVisualScene(scene_id);
|
|
|
|
|
scene_opened = true;
|
|
|
|
|
}
|
2017-04-21 16:15:41 +02:00
|
|
|
|
|
|
|
|
|
2017-04-19 11:48:52 +02:00
|
|
|
const std::vector<real_t> matrix = parent.transformation().matrix().data();
|
2017-04-13 16:39:36 +02:00
|
|
|
|
2017-04-19 11:48:52 +02:00
|
|
|
double matrix_array[4][4] = {
|
|
|
|
|
{ (double)matrix[0], (double)matrix[3], (double)matrix[6], (double)matrix[9] },
|
|
|
|
|
{ (double)matrix[1], (double)matrix[4], (double)matrix[7], (double)matrix[10] },
|
|
|
|
|
{ (double)matrix[2], (double)matrix[5], (double)matrix[8], (double)matrix[11] },
|
|
|
|
|
{ 0, 0, 0, 1 }
|
|
|
|
|
};
|
|
|
|
|
|
2017-04-21 16:15:41 +02:00
|
|
|
//adding the offset to the matrix
|
2017-04-19 11:48:52 +02:00
|
|
|
matrix_array[0][3] += serializer->settings().offset[0];
|
|
|
|
|
matrix_array[1][3] += serializer->settings().offset[1];
|
|
|
|
|
matrix_array[2][3] += serializer->settings().offset[2];
|
2017-04-19 15:09:59 +02:00
|
|
|
|
2017-04-19 11:48:52 +02:00
|
|
|
|
|
|
|
|
const std::string id = "representation-" + boost::lexical_cast<std::string>(parent.id());
|
|
|
|
|
|
2017-04-13 16:39:36 +02:00
|
|
|
current_node = new COLLADASW::Node(mSW);
|
2017-04-19 11:48:52 +02:00
|
|
|
current_node->setNodeId(id);
|
|
|
|
|
current_node->setNodeName(parent.name());
|
|
|
|
|
current_node->addMatrix(matrix_array);
|
2017-04-13 16:39:36 +02:00
|
|
|
current_node->setType(COLLADASW::Node::NODE);
|
|
|
|
|
current_node->start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColladaSerializer::ColladaExporter::ColladaScene::closeParent(){
|
2017-04-19 16:38:35 +02:00
|
|
|
if (current_node != NULL) { current_node->end(); }
|
2017-04-13 16:39:36 +02:00
|
|
|
}
|
|
|
|
|
|
2013-03-24 10:48:39 +00:00
|
|
|
void ColladaSerializer::ColladaExporter::ColladaScene::write() {
|
|
|
|
|
if (scene_opened) {
|
|
|
|
|
closeVisualScene();
|
|
|
|
|
closeLibrary();
|
2017-04-12 15:49:05 +02:00
|
|
|
|
2013-03-24 10:48:39 +00:00
|
|
|
COLLADASW::Scene scene (mSW, COLLADASW::URI ("#" + scene_id));
|
|
|
|
|
scene.add();
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-10 11:35:32 +02:00
|
|
|
|
|
|
|
|
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material)
|
|
|
|
|
{
|
2017-01-11 12:00:51 +02:00
|
|
|
std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES)
|
2016-03-10 12:01:04 +02:00
|
|
|
? material.original_name() : material.name());
|
2016-03-10 11:35:32 +02:00
|
|
|
collada_id(material_name);
|
|
|
|
|
openEffect(material_name + "-fx");
|
2013-03-24 10:48:39 +00:00
|
|
|
COLLADASW::EffectProfile effect(mSW);
|
|
|
|
|
effect.setShaderType(COLLADASW::EffectProfile::LAMBERT);
|
2013-05-11 15:26:35 +00:00
|
|
|
if (material.hasDiffuse()) {
|
|
|
|
|
const double* diffuse = material.diffuse();
|
|
|
|
|
effect.setDiffuse(COLLADASW::ColorOrTexture(COLLADASW::Color(diffuse[0],diffuse[1],diffuse[2])));
|
2013-05-05 08:49:25 +00:00
|
|
|
}
|
2013-05-11 15:26:35 +00:00
|
|
|
if (material.hasSpecular()) {
|
|
|
|
|
const double* specular = material.specular();
|
|
|
|
|
effect.setSpecular(COLLADASW::ColorOrTexture(COLLADASW::Color(specular[0],specular[1],specular[2])));
|
2013-05-05 08:49:25 +00:00
|
|
|
}
|
2013-05-11 15:26:35 +00:00
|
|
|
if (material.hasSpecularity()) {
|
|
|
|
|
effect.setShininess(material.specularity());
|
2013-05-05 08:49:25 +00:00
|
|
|
}
|
2013-05-11 15:26:35 +00:00
|
|
|
if (material.hasTransparency()) {
|
|
|
|
|
const double transparency = material.transparency();
|
2013-05-05 08:49:25 +00:00
|
|
|
if (transparency > 0) {
|
2013-12-27 09:33:57 +00:00
|
|
|
// The default opacity mode for Collada is A_ONE, which apparently indicates a
|
|
|
|
|
// transparency value of 1 to be fully opaque. Hence transparency is inverted.
|
|
|
|
|
effect.setTransparency(1.0 - transparency);
|
2013-05-05 08:49:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
2013-03-24 10:48:39 +00:00
|
|
|
addEffectProfile(effect);
|
2013-05-05 08:49:25 +00:00
|
|
|
closeEffect();
|
2013-03-24 10:48:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close() {
|
|
|
|
|
closeLibrary();
|
|
|
|
|
}
|
2016-03-10 11:35:32 +02:00
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeom::Material& material) {
|
2013-05-11 15:26:35 +00:00
|
|
|
if (!contains(material)) {
|
|
|
|
|
effects.write(material);
|
|
|
|
|
materials.push_back(material);
|
2013-03-24 10:48:39 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeom::Material& material) {
|
2013-05-11 15:26:35 +00:00
|
|
|
return std::find(materials.begin(), materials.end(), material) != materials.end();
|
2013-03-24 10:48:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColladaSerializer::ColladaExporter::ColladaMaterials::write() {
|
|
|
|
|
effects.close();
|
2016-03-10 11:35:32 +02:00
|
|
|
foreach(const IfcGeom::Material& material, materials) {
|
2017-01-11 12:00:51 +02:00
|
|
|
std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES)
|
2016-03-10 12:01:04 +02:00
|
|
|
? material.original_name() : material.name());
|
2016-03-10 11:35:32 +02:00
|
|
|
std::string material_name_unescaped = material_name; // workaround double-escaping that would occur in addInstanceEffect()
|
|
|
|
|
IfcUtil::sanitate_material_name(material_name_unescaped);
|
|
|
|
|
collada_id(material_name);
|
2013-03-24 10:48:39 +00:00
|
|
|
openMaterial(material_name);
|
2016-03-10 11:35:32 +02:00
|
|
|
addInstanceEffect("#" + material_name_unescaped + "-fx");
|
2013-12-27 09:33:57 +00:00
|
|
|
closeMaterial();
|
2013-03-24 10:48:39 +00:00
|
|
|
}
|
2013-12-27 09:33:57 +00:00
|
|
|
closeLibrary();
|
2013-03-24 10:48:39 +00:00
|
|
|
}
|
2016-03-10 11:35:32 +02:00
|
|
|
|
2013-12-31 14:10:38 +00:00
|
|
|
void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_name, float unit_magnitude) {
|
2013-03-24 10:48:39 +00:00
|
|
|
stream.startDocument();
|
|
|
|
|
|
|
|
|
|
COLLADASW::Asset asset(&stream);
|
|
|
|
|
asset.getContributor().mAuthoringTool = std::string("IfcOpenShell ") + IFCOPENSHELL_VERSION;
|
2013-12-31 14:10:38 +00:00
|
|
|
asset.setUnit(unit_name, unit_magnitude);
|
2013-03-24 10:48:39 +00:00
|
|
|
asset.setUpAxisType(COLLADASW::Asset::Z_UP);
|
|
|
|
|
asset.add();
|
|
|
|
|
}
|
2017-04-12 14:38:54 +02:00
|
|
|
|
2017-04-21 15:49:34 +02:00
|
|
|
void ColladaSerializer::ColladaExporter::write(const IfcGeom::TriangulationElement<real_t>* o)
|
2017-04-12 14:38:54 +02:00
|
|
|
{
|
|
|
|
|
const IfcGeom::Representation::Triangulation<real_t>& mesh = o->geometry();
|
|
|
|
|
const std::string name = serializer->settings().get(SerializerSettings::USE_ELEMENT_GUIDS) ?
|
2017-04-19 12:07:03 +02:00
|
|
|
o->guid() : (serializer->settings().get(SerializerSettings::USE_ELEMENT_NAMES) ?
|
2017-04-19 16:38:35 +02:00
|
|
|
o->name() : (serializer->settings().get(SerializerSettings::USE_ELEMENT_TYPES) ? o->type() : o->unique_id()));
|
2017-04-12 14:38:54 +02:00
|
|
|
const std::string representation_id = "representation-" + boost::lexical_cast<std::string>(o->geometry().id());
|
|
|
|
|
std::vector<std::string> material_references;
|
|
|
|
|
foreach(const IfcGeom::Material& material, mesh.materials()) {
|
|
|
|
|
if (!materials.contains(material)) {
|
|
|
|
|
materials.add(material);
|
|
|
|
|
}
|
|
|
|
|
std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES)
|
|
|
|
|
? material.original_name() : material.name());
|
|
|
|
|
collada_id(material_name);
|
|
|
|
|
material_references.push_back(material_name);
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-19 15:09:59 +02:00
|
|
|
DeferredObject defered = (serializer->settings().get(SerializerSettings::USE_ELEMENT_HIERARCHY) ?
|
2017-04-12 14:38:54 +02:00
|
|
|
DeferredObject(name, representation_id, o->type(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(),
|
2017-04-21 15:49:34 +02:00
|
|
|
mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials(), material_references, mesh.uvs(), *(o->storey())) :
|
2017-04-12 14:38:54 +02:00
|
|
|
DeferredObject(name, representation_id, o->type(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(),
|
2017-04-19 15:09:59 +02:00
|
|
|
mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials(), material_references, mesh.uvs()));
|
|
|
|
|
deferreds.push_back(defered);
|
|
|
|
|
|
2017-04-12 14:38:54 +02:00
|
|
|
}
|
2017-04-11 17:26:30 +02:00
|
|
|
|
2013-03-24 10:48:39 +00:00
|
|
|
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();
|
2017-04-21 16:15:41 +02:00
|
|
|
|
|
|
|
|
|
2016-03-18 11:23:25 +01:00
|
|
|
std::set<std::string> geometries_written;
|
2017-04-21 16:15:41 +02:00
|
|
|
|
|
|
|
|
//if the setting USE_ELEMENT_HIERARCHY is in use, we sort the deferreds objects by their parents.
|
|
|
|
|
if (serializer->settings().get(SerializerSettings::USE_ELEMENT_HIERARCHY)) {
|
|
|
|
|
std::sort(deferreds.begin(), deferreds.end());
|
|
|
|
|
}
|
2014-01-02 13:57:34 +00:00
|
|
|
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
|
2016-03-18 11:23:25 +01:00
|
|
|
if (geometries_written.find(it->representation_id) != geometries_written.end()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
geometries_written.insert(it->representation_id);
|
2016-03-22 16:15:28 +01:00
|
|
|
geometries.write(it->representation_id, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials, it->uvs);
|
2013-03-24 10:48:39 +00:00
|
|
|
}
|
|
|
|
|
geometries.close();
|
2017-04-21 16:15:41 +02:00
|
|
|
|
2017-04-19 15:09:59 +02:00
|
|
|
int parent_id = -1;
|
|
|
|
|
bool is_parent_empty = true;
|
2017-04-21 16:15:41 +02:00
|
|
|
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it){
|
2015-05-13 14:30:21 +00:00
|
|
|
const std::string object_name = it->unique_id;
|
2017-04-19 16:38:35 +02:00
|
|
|
|
2017-04-21 16:15:41 +02:00
|
|
|
//if the setting USE_ELEMENT_HIERARCHY is in use, we check if the parent changed
|
|
|
|
|
if (serializer->settings().get(SerializerSettings::USE_ELEMENT_HIERARCHY) && it->parent != NULL && parent_id != it->parent->id()){
|
|
|
|
|
|
|
|
|
|
//close the parent tag, if one is already open.
|
|
|
|
|
if (!is_parent_empty){
|
2017-04-13 16:39:36 +02:00
|
|
|
scene.closeParent();
|
|
|
|
|
}
|
2017-04-19 11:48:52 +02:00
|
|
|
parent_id = it->parent->id();
|
|
|
|
|
scene.addParent(*it->parent);
|
2017-04-13 16:39:36 +02:00
|
|
|
is_parent_empty = false;
|
|
|
|
|
}
|
2017-04-21 16:15:41 +02:00
|
|
|
|
2017-02-24 16:46:14 +02:00
|
|
|
/// @todo redundant information using ID as both ID and Name, maybe omit Name or allow specifying what would be used as the name
|
2016-03-18 11:23:25 +01:00
|
|
|
scene.add(object_name, object_name, it->representation_id, it->material_references, it->matrix);
|
2013-03-24 10:48:39 +00:00
|
|
|
}
|
2017-04-21 16:15:41 +02:00
|
|
|
//close the last parent tag.
|
|
|
|
|
if (!is_parent_empty) {
|
|
|
|
|
scene.closeParent();
|
|
|
|
|
};
|
2013-03-24 10:48:39 +00:00
|
|
|
scene.write();
|
|
|
|
|
stream.endDocument();
|
|
|
|
|
}
|
2016-03-10 11:35:32 +02:00
|
|
|
|
2013-03-24 10:48:39 +00:00
|
|
|
bool ColladaSerializer::ready() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColladaSerializer::writeHeader() {
|
2013-12-31 14:10:38 +00:00
|
|
|
exporter.startDocument(unit_name, unit_magnitude);
|
2013-03-24 10:48:39 +00:00
|
|
|
}
|
|
|
|
|
|
2016-03-10 11:35:32 +02:00
|
|
|
void ColladaSerializer::write(const IfcGeom::TriangulationElement<real_t>* o) {
|
2017-04-21 15:49:34 +02:00
|
|
|
exporter.write(o);
|
2017-04-12 14:56:00 +02:00
|
|
|
}
|
|
|
|
|
|
2017-04-12 14:38:54 +02:00
|
|
|
|
2013-03-24 10:48:39 +00:00
|
|
|
void ColladaSerializer::finalize() {
|
|
|
|
|
exporter.endDocument();
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-22 08:23:11 +00:00
|
|
|
#endif
|