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 <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 ;
2017-09-10 16:59:05 +02:00
static std : : string & collada_id ( std : : string & s )
2016-03-10 11:35:32 +02:00
{
IfcUtil : : sanitate_material_name ( s ) ;
IfcUtil : : escape_xml ( s ) ;
2017-09-10 16:59:05 +02:00
return 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 (
2017-05-20 19:50:10 +02:00
const std : : string & mesh_id , const std : : string & /*default_material_name*/ , const std : : vector < real_t > & positions ,
2016-03-10 11:35:32 +02:00
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 ,
2017-05-20 19:50:10 +02:00
const std : : vector < std : : string > & material_ids , const IfcGeom : : Transformation < real_t > & transformation )
2016-03-10 11:35:32 +02:00
{
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.
2017-05-20 19:50:10 +02:00
IfcGeom : : Transformation < real_t > * relative_trsf = 0 ;
const IfcGeom : : Transformation < real_t > * transformation_towrite = & transformation ;
2017-05-15 17:45:05 +02:00
// If this is not the first parent, get the relative placement
if ( parentNodes . size ( ) > 0 )
{
2017-05-20 19:50:10 +02:00
relative_trsf = new IfcGeom : : Transformation < real_t > ( matrixStack . top ( ) . multiplied ( transformation ) ) ;
transformation_towrite = relative_trsf ;
}
2013-03-24 10:48:39 +00:00
2017-05-20 19:50:10 +02:00
const std : : vector < real_t > & posmatrix = transformation_towrite - > matrix ( ) . data ( ) ;
2017-05-15 17:45:05 +02:00
2017-05-20 19:50:10 +02:00
double matrix_array [ 4 ] [ 4 ] = {
{ ( double ) posmatrix [ 0 ] , ( double ) posmatrix [ 3 ] , ( double ) posmatrix [ 6 ] , ( double ) posmatrix [ 9 ] } ,
{ ( double ) posmatrix [ 1 ] , ( double ) posmatrix [ 4 ] , ( double ) posmatrix [ 7 ] , ( double ) posmatrix [ 10 ] } ,
{ ( double ) posmatrix [ 2 ] , ( double ) posmatrix [ 5 ] , ( double ) posmatrix [ 8 ] , ( double ) posmatrix [ 11 ] } ,
{ 0 , 0 , 0 , 1 }
} ;
2017-05-15 17:45:05 +02:00
2017-05-20 19:50:10 +02:00
/// @todo: TFK: Rather than applying this offset to all leafs (which might be undesirable) should this offset be applied to a node higher up in the hierarchy?
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 ] ;
2017-05-20 19:50:10 +02:00
delete relative_trsf ;
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-05-20 19:50:10 +02:00
const IfcGeom : : Transformation < real_t > & parent_trsf = parent . transformation ( ) ;
IfcGeom : : Transformation < real_t > * relative_trsf = 0 ;
const IfcGeom : : Transformation < real_t > * transformation_towrite = & parent_trsf ;
// If this is not the first parent, get the relative placement
if ( parentNodes . size ( ) > 0 )
{
relative_trsf = new IfcGeom : : Transformation < real_t > ( matrixStack . top ( ) . multiplied ( parent_trsf ) ) ;
transformation_towrite = relative_trsf ;
}
const std : : vector < real_t > & parentMatrix = transformation_towrite - > matrix ( ) . data ( ) ;
2017-04-21 16:15:41 +02:00
2017-04-19 11:48:52 +02:00
double matrix_array [ 4 ] [ 4 ] = {
2017-05-15 17:45:05 +02:00
{ ( double ) parentMatrix [ 0 ] , ( double ) parentMatrix [ 3 ] , ( double ) parentMatrix [ 6 ] , ( double ) parentMatrix [ 9 ] } ,
{ ( double ) parentMatrix [ 1 ] , ( double ) parentMatrix [ 4 ] , ( double ) parentMatrix [ 7 ] , ( double ) parentMatrix [ 10 ] } ,
{ ( double ) parentMatrix [ 2 ] , ( double ) parentMatrix [ 5 ] , ( double ) parentMatrix [ 8 ] , ( double ) parentMatrix [ 11 ] } ,
2017-04-19 11:48:52 +02:00
{ 0 , 0 , 0 , 1 }
} ;
2017-05-16 14:27:36 +02:00
// Chose a name of the parent object
std : : string name = " " ;
2017-05-20 19:50:10 +02:00
if ( serializer - > settings ( ) . get ( SerializerSettings : : USE_ELEMENT_TYPES ) ) {
name = parent . type ( ) + " " + parent . name ( ) ;
} else {
name = parent . unique_id ( ) ;
2017-05-18 11:26:19 +02:00
}
2017-09-10 16:59:05 +02:00
collada_id ( name ) ;
2017-05-20 19:50:10 +02:00
const std : : string & id = name ;
2017-05-16 14:27:36 +02:00
2017-05-15 17:45:05 +02:00
COLLADASW : : Node * current_node ;
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 ) ;
2017-05-16 14:27:36 +02:00
current_node - > setNodeName ( name ) ;
2017-04-13 16:39:36 +02:00
current_node - > setType ( COLLADASW : : Node : : NODE ) ;
current_node - > start ( ) ;
2017-05-16 11:27:45 +02:00
current_node - > addMatrix ( matrix_array ) ;
2017-05-15 17:45:05 +02:00
// Add the node to the parent stack
2017-05-20 19:50:10 +02:00
matrixStack . push ( parent_trsf . inverted ( ) ) ;
2017-05-15 17:45:05 +02:00
parentNodes . push ( current_node ) ;
serializer - > parentStackId . push ( parent . id ( ) ) ;
2017-04-13 16:39:36 +02:00
}
2017-05-15 17:45:05 +02:00
void ColladaSerializer : : ColladaExporter : : ColladaScene : : closeParent ( )
{
// Get the top element
COLLADASW : : Node * current_node = parentNodes . top ( ) ;
// Close the node
current_node - > end ( ) ;
// Remove it from the stack
parentNodes . pop ( ) ;
matrixStack . pop ( ) ;
serializer - > parentStackId . pop ( ) ;
// Free the memory
delete current_node ;
current_node = NULL ;
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 ( ) ;
2017-04-25 16:27:14 +02:00
std : : string slabSuffix = " " ;
if ( o - > type ( ) = = " IfcSlab " )
{
2017-04-26 10:28:38 +02:00
slabSuffix = differentiateSlabTypes ( o ) ;
2017-04-25 16:27:14 +02:00
}
2017-09-10 16:59:05 +02:00
std : : string name = serializer - > settings ( ) . get ( SerializerSettings : : USE_ELEMENT_GUIDS )
? o - > guid ( )
: ( serializer - > settings ( ) . get ( SerializerSettings : : USE_ELEMENT_NAMES )
? o - > name ( )
: ( serializer - > settings ( ) . get ( SerializerSettings : : USE_ELEMENT_TYPES )
? ( o - > type ( ) + slabSuffix )
: o - > unique_id ( ) ) ) ;
collada_id ( name ) ;
std : : string representation_id = " representation- " + o - > geometry ( ) . id ( ) ;
collada_id ( representation_id ) ;
2017-04-12 14:38:54 +02:00
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-05-20 19:50:10 +02:00
DeferredObject deferred ( name , representation_id , o - > type ( ) , o - > transformation ( ) , mesh . verts ( ) , mesh . normals ( ) ,
mesh . faces ( ) , mesh . edges ( ) , mesh . material_ids ( ) , mesh . materials ( ) , material_references , mesh . uvs ( ) ) ;
if ( serializer - > settings ( ) . get ( SerializerSettings : : USE_ELEMENT_HIERARCHY ) ) {
deferred . parents ( ) = o - > parents ( ) ;
}
deferreds . push_back ( deferred ) ;
2017-04-26 10:28:38 +02:00
}
std : : string ColladaSerializer : : ColladaExporter : : differentiateSlabTypes ( const IfcGeom : : TriangulationElement < real_t > * o ) {
IfcSlab * slab = ( IfcSlab * ) o - > product ( ) ;
2017-09-10 16:59:05 +02:00
std : : string result ;
2017-05-09 15:55:37 +02:00
switch ( slab - > PredefinedType ( ) )
{
case ( IfcSlabTypeEnum : : IfcSlabType_FLOOR ) :
2017-09-10 16:59:05 +02:00
result = " _Floor " ;
2017-05-09 15:55:37 +02:00
break ;
case ( IfcSlabTypeEnum : : IfcSlabType_ROOF ) :
2017-09-10 16:59:05 +02:00
result = " _Roof " ;
2017-05-09 15:55:37 +02:00
break ;
case ( IfcSlabTypeEnum : : IfcSlabType_LANDING ) :
2017-09-10 16:59:05 +02:00
result = " _Landing " ;
2017-05-09 15:55:37 +02:00
break ;
case ( IfcSlabTypeEnum : : IfcSlabType_BASESLAB ) :
2017-09-10 16:59:05 +02:00
result = " _BaseSlab " ;
2017-05-09 15:55:37 +02:00
break ;
case ( IfcSlabTypeEnum : : IfcSlabType_NOTDEFINED ) :
2017-09-10 16:59:05 +02:00
result = " _NotDefined " ;
2017-05-09 15:55:37 +02:00
break ;
default :
2017-09-10 16:59:05 +02:00
if ( slab - > hasObjectType ( ) ) { result = " _ " + slab - > ObjectType ( ) ; }
else { result = " _Unknown " ; }
2017-05-09 15:55:37 +02:00
break ;
}
2017-09-10 16:59:05 +02:00
collada_id ( result ) ;
return result ;
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-25 11:55:09 +02:00
bool use_hierarchy = serializer - > settings ( ) . get ( SerializerSettings : : USE_ELEMENT_HIERARCHY ) ;
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.
2017-05-15 17:45:05 +02:00
2017-04-25 11:55:09 +02:00
if ( use_hierarchy ) {
2017-04-21 16:15:41 +02:00
std : : sort ( deferreds . begin ( ) , deferreds . end ( ) ) ;
}
2017-05-15 17:45:05 +02:00
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
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-05-15 17:45:05 +02:00
if ( use_hierarchy )
{
2017-06-05 18:53:57 +03:00
size_t parentsNumber = it - > parents_ . size ( ) ;
2017-05-15 17:45:05 +02:00
bool finished = false ;
2017-05-16 15:01:55 +02:00
// If we have no parent in the stack and the object has no parent, nothing to do : skip the loop
if ( parentsNumber = = 0 & & serializer - > parentStackId . size ( ) = = 0 ) { finished = true ; }
2017-05-15 17:45:05 +02:00
while ( ! finished )
{
// If we need to add a parent
if ( serializer - > parentStackId . size ( ) < = parentsNumber )
{
2017-05-20 19:50:10 +02:00
if ( serializer - > parentStackId . empty ( ) ) { scene . addParent ( * ( it - > parents_ . at ( 0 ) ) ) ; }
2017-05-15 17:45:05 +02:00
else
{
2017-06-05 18:53:57 +03:00
size_t diff = parentsNumber - serializer - > parentStackId . size ( ) ;
2017-05-15 17:45:05 +02:00
// If we have the wrong parent in the list
2017-05-20 19:50:10 +02:00
if ( serializer - > parentStackId . top ( ) ! = it - > parents_ . at ( parentsNumber - diff - 1 ) - > id ( ) ) {
2017-05-15 17:45:05 +02:00
scene . closeParent ( ) ;
2017-05-20 19:50:10 +02:00
} else {
// So far we have the right parents, we just need to add the missing ones
2017-06-05 18:53:57 +03:00
for ( size_t i = parentsNumber - diff ; i < parentsNumber ; i + + ) { scene . addParent ( * ( it - > parents_ . at ( i ) ) ) ; }
2017-05-15 17:45:05 +02:00
// if diff == 0, we can leave the loop. In fact we have the right number of parents, and the last one is ok
if ( diff = = 0 ) { finished = true ; }
}
}
2017-05-20 19:50:10 +02:00
} else {
2017-05-15 17:45:05 +02:00
// Close the finished nodes. After this we get the first case (serializer->parentStackId.size() <= parentsNumber)
while ( serializer - > parentStackId . size ( ) > parentsNumber ) { scene . closeParent ( ) ; }
}
2017-04-21 18:05:35 +02:00
}
2017-04-13 16:39:36 +02:00
}
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
2017-05-20 19:50:10 +02:00
scene . add ( object_name , object_name , it - > representation_id , it - > material_references , it - > transformation ) ;
2013-03-24 10:48:39 +00:00
}
2017-05-15 17:45:05 +02:00
//close the remaining parent tags.
while ( serializer - > parentStackId . size ( ) > 0 ) { 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
}
2013-03-24 10:48:39 +00:00
void ColladaSerializer : : finalize ( ) {
exporter . endDocument ( ) ;
}
2013-11-22 08:23:11 +00:00
# endif