IFC(BIM)
BIM管理中使用的模型格式:IFC
IFC简介
IFC模型体系结构由四个层次构成,
从下到上依次是 资源层(Resource Layer)、核心层(Core Layer)、交互层(Interoperability Layer)、领域层(Domain Layer)。
每层中都包含一系列的信息描述模块,并且遵守一个规则:每个层次只能引用同层次和下层的信息资源,而不能引用上层的资源,当上层资源发生变动时,下层是不会受到影响的。
①资源层
IFC体系架构中的最低层,能为其他层所引用。主要是描述标准中用到的基本信息,不针对具体的行业本身,是无整体结构的分散信息,作为描述基础应用于整个信息模型。包括材料资源(Material Resource)、几何限制资源(Geometric Constraint Resource)、成本资源(Costs Resource)等。
②核心层
是IFC体系架构中的第二层,能为交互层与领域层所引用。主要是提供基础的IFC对象模型结构,描述建筑工程信息的整体框架,将资源层信息组织起来,成为一个整体,来反映现实世界的结构。包括核心(The Kernel)和核心扩展(Core Extensions)两个层次的泛化。
③交互层
是IFC体系架构中的第三层,主要是为领域层服务。领域层中的模型可以通过该层来达到信息交互的目的。该层主要解决了领域信息交互的问题,并且在这个层次使各个系统的组成元素细化。包括共享空间元素(SharedSpatialElements)、共享建筑元素(SharedBuildingElements)、共享管理元素(SharedManagement Elements)、共享设备元素(SharedFacilities Elements)和共享建筑服务元素(Shared Bldg Services Elements)等五大类。
④领域层
是IFC体系架构中的最高层。每一个使用或是引用定义在核心和独立资源层上的类信息的模型都是独立的。其主要作用时是深入到各个应用领域的内部,形成专题信息,比如暖通领域(HVAC Domain)、T程管理领域(Construction Management Domain)等,而且还可以根据实际需要不断进行扩展。
==================================================
1) IFC 标准资源层(IFC-Resource Layer):作为整个体系的基本层,IFC 任意层都可引用资源层中的实体。该层主要定义了工程项目的通用信息,这些信息独立于具体建筑,没有整体结构,是分散的基础信息。该层核心内容主要包括属性资源(Property Resource)、表现资源 (Representation Re-source)、结构资源(Structure Resource)。这些实体资源主要用于上层实体资源的定义,以显示上层实体的属性。
2) IFC 标准核心层(IFC-Core Layer):该层之中主要定义了产品、过程、控制等相关信息,主要作用是将下层分散的基础信息组织起来,形成 IFC 模型的基本结构,然后用以描述现实世界中的实物以及抽象的流程。在整个体系之中起到了承上启下的作用。该层提炼定义了适用于整个建筑行业的抽象概念,比如 IFCProduct 实体可以描述建筑项目的建筑场地、建筑空间、建筑构件等。
3) IFC 标准共享层(IFC-Interoperability Layer):共享层主要是服务于领域层,使各个领域间的信息能够交互,同时细化系统的组成元素,具体的建筑构件如板(IFCSlab)、柱(IFCColumn)、梁(IFCBeam)均在这一层被定义。
4) IFC 标准领域层(IFC-Domain Layer):作为 IFC 体系架构的顶层,该层主要定义了面向各个专业领域的实体类型。这些实体都面向各个专业领域具有特定的概念。比如暖通领域(HVAC Domain)的锅炉、管道等。
==================================================
楼层(IfcBuildingStorey):定义水平空间的垂直边界,具有标高属性。楼层与建筑存在关联关系,多个楼层组成了整体的建筑空间,一个楼层可能跨越几个连续的楼层形成复合建筑楼层。
设施(IfcFacility):定义基础设施,例如建筑、道路、桥梁等。
设施组件(IfcFacilityPart):定义基础设施中的组成部分,如桥梁组件(IfcBridgePart)。
场地(IfcSite):定义一个陆地区域,场地可以包括该场地的单个地理参考点的定义(使用经度,纬度和海拔的全球位置)。
空间(IfcSpace):表达具体或抽象的区域边界,是建筑内提供一定功能的区域面积或体积。空间与楼层关联可表示楼层上的房间划分,而与场地关联可表示场地中特定的功能区域。一个空间可能与几个连续的空间形成空间组合,也可以被分解成多个空间。
一个基于IFC标准的建筑信息模型有且只能定义一个项目(IfcProject)来作为项目中所有对象的容器,建筑构件大多与楼层或者楼层所拆分的空间建立关联关系,从而确定从属关系以及构件在整个三维模型中的坐标定位。集合关系(IfcRelAggregates)定义一对多的不同空间层次间的从属关系,子空间相互之间通过该关系对象建立从属关系,最终空间结构元素通过该关系对象与项目(IfcProject)建立从属关系。实际的建筑信息模型中可通过集合关系建立一个完整的信息模型空间。
==================================================
IFC格式架构
IFC架构采用EXPRESS语言定义,EXPRESS语言是由STEP开发的概念性架构语言。EXPRESS用于面向对象的信息描述语言,处于STEP的基础和核心地位。它将IFC模型的结构描述为:规范的类,与类相关联的属性,类的约束,以及类与其他约束之间的关系。
IFC架构分为四个层:领域层、共享层、核心层、资源层。
IFC架构将所有的对象与类按概念进行分类:类型、实体、函数、规则、属性集及量集。
IFC数据组成
IFC文件是一种纯文本文件格式,用普通的文本编辑器就可以查看和编辑。
文件以“ISO-10303-21;”开头,以“END-ISO-10303-21;”结束。
中间包括两个部分:一个文件头段和一个数据段。
文件头段以“HEADER;”开始,以“ENDSEC;”结束,里面包含了有关ifc文件本身的信息,例如文件描述、使用的ifc标准版本等。
数据段以“DATA;”开始,以“ENDSEC;”结束,里面包含了要交换的工程信息。
IFC格式优势
使用IFC格式有以下优势:
- 实现不同软件之间的信息交换
IFC作为一个标准的公开的数据表达和存储方法,不同软件通过对接IFC标准接口,便可以与其他软件系统交换信息,畅通无阻。
- 提升建筑项目中的沟通、生产力、时间、成本和质量
通过IFC,可以在建筑项目的整个生命周期中提升沟通、生产力、时间、成本和质量,为全球的建筑专业与设备专业中的流程提升与信息共享建立一个普遍意义的基准。
- 集中存储多个项目的工程信息
BIM数据库可集中存储多个项目的工程信息,并利用文件管理表、语句管理表和属性管理表对IFC模型进行保存,从而保证IFC建筑信息模型的正确性和完整性。
- 建筑信息查询效率高
BIM数据库利用文件管理表、语句管理表和属性管理表对IFC模型进行保存,使建筑信息查询效率大大提升。
IFC格式查看与转换
要打开IFC文件,可以使用以下软件:
- Autodesk Revit
Revit是一种建筑信息建模(BIM)软件,支持IFC格式,并可用于导入、编辑和查看IFC文件。
- Tekla Structures
这是一种结构工程BIM软件,也可以打开和编辑IFC文件。
- 在线工具
推荐使用NSDT 3DConvert这个强大的在线3D格式转换工具,可以将IFC、STEP、IGES、3DXML等多种BIM/CAD文件转换为GLTF、STL、OBJ、DAE等格式。
==================================================================
OSG与IFC
读写IFC文件的osg插件(osgdb_ifc)
调用第三方库ifcplusplus 实现osg ifc插件
第三方库:https://github.com/ifcquery/ifcplusplus
转自:https://blog.csdn.net/baidu_41914439/article/details/108078092?spm=1001.2014.3001.5502
//ReaderWriterIFC.h #ifndef READERWRITERIFC_H #define READERWRITERIFC_H#include <osgDB/ReaderWriter>/// // OSG reader plugin for the ".ifc" format. // // This plugin requires the ifcplusplusclass BuildingModel; class BuildingEntity; class ReaderSTEP; class WriterSTEP; class GeometryConverter;class ReaderWriterIFC : public osgDB::ReaderWriter {osg::ref_ptr<osg::Group> m_rootnode;osg::ref_ptr<osg::Switch> m_sw_coord_axes;osg::ref_ptr<osg::Switch> m_sw_model; shared_ptr<GeometryConverter> m_geometry_converter;shared_ptr<ReaderSTEP> m_step_reader;shared_ptr<WriterSTEP> m_step_writer; shared_ptr<BuildingModel> m_ifc_model;public:ReaderWriterIFC();const char* className() const { return "IFC reader/writer"; }virtual ReadResult readObject(const std::string& filename, const Options* options) const{return readNode(filename, options);}virtual WriteResult writeObject(const osg::Node& node, const std::string& filename, const Options* options) const{return writeNode(node, filename, options);}virtual ReadResult readNode(const std::string& filename, const Options*) const;virtual WriteResult writeNode(const osg::Node&, const std::string& filename, const Options*) const; };/// #endif
//ReaderWriterIFC.cpp #include <sstream> #include <memory> #ifndef WIN32 #include <strings.h>//for strncasecmp #endif//#include <osg/Notify> //#include <osg/MatrixTransform> //#include <osg/Material> #include <osg/StatusCallback> #include <osg/PositionAttitudeTransform> //#include <osg/Texture2D> //#include <osg/Version> //#include <osgDB/ConvertUTF> #include <osgDB/FileNameUtils> #include <osgDB/FileUtils> //#include <osgDB/ReadFile> //#include <osgDB/Registry> #include <osgUtil/Optimizer> //#include <osgAnimation/AnimationManagerBase> //#include <osgAnimation/Bone> //#include <osgAnimation/RigGeometry> //#include <osgAnimation/Skeleton> //#include <osgAnimation/VertexInfluence> //#include <osgGA/GUIActionAdapter> #include <ifcpp/model/BasicTypes.h> #include <ifcpp/model/BuildingModel.h> #include <ifcpp/model/BuildingException.h> #include <ifcpp/model/BuildingGuid.h> #include <ifcpp/reader/ReaderSTEP.h> #include <ifcpp/reader/ReaderUtil.h> #include <ifcpp/writer/WriterSTEP.h> #include <ifcpp/IFC4/include/IfcProduct.h> #include <ifcpp/IFC4/include/IfcSite.h> #include <ifcpp/IFC4/include/IfcLengthMeasure.h> #include <ifcpp/IFC4/include/IfcOpeningElement.h> #include <ifcpp/IFC4/include/IfcOwnerHistory.h> #include <ifcpp/IFC4/include/IfcGloballyUniqueId.h> #include <ifcpp/geometry/Carve/GeometryConverter.h> #include <ifcpp/geometry/Carve/ConverterOSG.h>#if defined(_MSC_VER)#pragma warning( disable : 4505 )#pragma warning( default : 4996 ) #endif#include "ReaderWriterIFC.h"/// Returns true if the given node is a basic root group with no special information. /// Used in conjunction with UseFbxRoot option. /// Identity transforms are considered as basic root nodes. bool isBasicRootNode(const osg::Node& node) {const osg::Group* osgGroup = node.asGroup();if (!osgGroup || node.asGeode()) // WriterNodeVisitor handles Geodes the "old way" (= Derived from Node, not Group as for now). Geodes may be considered "basic root nodes" when WriterNodeVisitor will be adapted. {// Geodes & such are not basic root nodesreturn false;}// Test if we've got an empty transform (= a group!)const osg::Transform* transform = osgGroup->asTransform(); if (transform){const osg::PositionAttitudeTransform* pat = transform->asPositionAttitudeTransform();if (const osg::MatrixTransform* matrixTransform = transform->asMatrixTransform()){if (!matrixTransform->getMatrix().isIdentity()){// Non-identity matrix transformreturn false;}}else if ( pat ){if (pat->getPosition() != osg::Vec3d() ||pat->getAttitude() != osg::Quat() ||pat->getScale() != osg::Vec3d(1.0f, 1.0f, 1.0f) ||pat->getPivotPoint() != osg::Vec3d()){// Non-identity position attribute transformreturn false;}}else{// Other transform (not identity or not predefined type)return false;}}// Test the presence of a non-empty statesetif (node.getStateSet()){osg::ref_ptr<osg::StateSet> emptyStateSet = new osg::StateSet;if (node.getStateSet()->compare(*emptyStateSet, true) != 0){return false;}}return true; }ReaderWriterIFC::ReaderWriterIFC() {supportsExtension("ifc", "IFC format");supportsOption("Embedded", "(Write option) Embed textures in IFC file");supportsOption("UseFbxRoot", "(Read/write option) If the source OSG root node is a simple group with no stateset, the writer will put its children directly under the IFC root, and vice-versa for reading");supportsOption("LightmapTextures", "(Read option) Interpret texture maps as overriding the lighting. 3D Studio Max may export files that should be interpreted in this way.");supportsOption("TessellatePolygons", "(Read option) Tessellate mesh polygons. If the model contains concave polygons this may be necessary, however tessellating can be very slow and may erroneously produce triangle shards.");m_ifc_model = shared_ptr<BuildingModel>(new BuildingModel());m_geometry_converter = shared_ptr<GeometryConverter>(new GeometryConverter(m_ifc_model));m_step_reader = shared_ptr<ReaderSTEP>(new ReaderSTEP());m_step_writer = shared_ptr<WriterSTEP>(new WriterSTEP());m_rootnode = new osg::Group();m_rootnode->setName("m_rootnode");m_sw_model = new osg::Switch();m_sw_model->setName("m_sw_model");m_rootnode->addChild(m_sw_model.get());m_sw_coord_axes = new osg::Switch();m_sw_coord_axes->setName("m_sw_coord_axes");m_rootnode->addChild(m_sw_coord_axes.get()); } std::wstring StringToWstring(const std::string str) {// string转wstringunsigned len = str.size() * 2;// 预留字节数setlocale(LC_CTYPE, ""); //必须调用此函数wchar_t *p = new wchar_t[len];// 申请一段内存存放转换后的字符串mbstowcs(p, str.c_str(), len);// 转换 std::wstring str1(p);delete[] p;// 释放申请的内存return str1; } osgDB::ReaderWriter::ReadResult ReaderWriterIFC::readNode(const std::string& filenameInit,const Options* options) const {try{std::string ext(osgDB::getLowerCaseFileExtension(filenameInit));if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;std::string filename(osgDB::findDataFile(filenameInit, options));if (filename.empty()) return ReadResult::FILE_NOT_FOUND;// first remove previously loaded geometry from scenegraphosg::ref_ptr<osg::Switch> model_switch = m_sw_model; SceneGraphUtils::clearAllChildNodes(model_switch);// reset the IFC modelshared_ptr<GeometryConverter> geometry_converter = m_geometry_converter;geometry_converter->clearMessagesCallback();geometry_converter->resetModel();std::stringstream err;try{osg::StatusCallback& statusCallBack = osg::StatusCallback::getStatusCallback();void* obj = statusCallBack.getMessageCallBack_obj();osg::StatusCallback::Func_call_on_message func = statusCallBack.getMessageCallBack_func();geometry_converter->setMessageCallBack_extern(obj,func);m_step_reader->setMessageCallBack_extern(obj, func);// load file to IFC modelstd::wstring fileName = StringToWstring(filenameInit);m_step_reader->loadModelFromFile(fileName, geometry_converter->getBuildingModel());// convert IFC geometric representations into Carve geometryconst double length_in_meter = geometry_converter->getBuildingModel()->getUnitConverter()->getLengthInMeterFactor();geometry_converter->setCsgEps(1.5e-08*length_in_meter);geometry_converter->convertGeometry();// convert Carve geometry to OSGshared_ptr<ConverterOSG> converter_osg(new ConverterOSG(geometry_converter->getGeomSettings()));converter_osg->setMessageCallBack_extern(obj, func);converter_osg->convertToOSG(geometry_converter->getShapeInputData(), model_switch);// in case there are IFC entities that are not in the spatial structureconst std::map<std::string, shared_ptr<BuildingObject> >& objects_outside_spatial_structure = geometry_converter->getObjectsOutsideSpatialStructure();if (objects_outside_spatial_structure.size() > 0){osg::ref_ptr<osg::Switch> sw_objects_outside_spatial_structure = new osg::Switch();sw_objects_outside_spatial_structure->setName("IfcProduct objects outside spatial structure");converter_osg->addNodes(objects_outside_spatial_structure, sw_objects_outside_spatial_structure);if (sw_objects_outside_spatial_structure->getNumChildren() > 0){model_switch->addChild(sw_objects_outside_spatial_structure);}}}catch (OutOfMemoryException& e){throw e;}catch (BuildingException& e){err << e.what();}catch (std::exception& e){err << e.what();}catch (...){err << "loadModelFromFile, createGeometryOSG failed" << std::endl;}try{if (model_switch){bool optimize = true;if (optimize){osgUtil::Optimizer opt;opt.optimize(model_switch);}// if model bounding sphere is far from origin, move to originconst osg::BoundingSphere& bsphere = model_switch->getBound();if (bsphere.center().length() > 10000){if (bsphere.center().length() / bsphere.radius() > 100){std::unordered_set<osg::Geode*> set_applied;SceneGraphUtils::translateGroup(model_switch, -bsphere.center(), set_applied);}}}}catch (std::exception& e){err << e.what();}geometry_converter->clearInputCache();if (err.tellp() > 0){throw BuildingException(err.str().c_str());}bool refCoordSysChange = false;osg::Matrix mat;//if (zUp) {//if (eUp != FbxAxisSystem::eZAxis || fSign != 1.0 || upSign != 1.0) {/* switch (eUp){case FbxAxisSystem::eXAxis:mat.set(0, fSign, 0, 0, -fSign, 0, 0, 0, 0, 0, HorizSign, 0, 0, 0, 0, 1);break;case FbxAxisSystem::eYAxis:mat.set(1, 0, 0, 0, 0, 0, -fSign * HorizSign, 0, 0, fSign, 0, 0, 0, 0, 0, 1);break;case FbxAxisSystem::eZAxis:mat.set(1, 0, 0, 0, 0, fSign, 0, 0, 0, 0, fSign * HorizSign, 0, 0, 0, 0, 1);break;}*/refCoordSysChange = true;}}//else //if (fbxAxis != FbxAxisSystem::OpenGL) {//switch (eUp)//{//case FbxAxisSystem::eXAxis:// mat.set(0, -fSign, 0, 0, fSign, 0, 0, 0, 0, 0, HorizSign, 0, 0, 0, 0, 1);// break;//case FbxAxisSystem::eYAxis:// mat.set(1, 0, 0, 0, 0, -fSign, 0, 0, 0, 0, -fSign * HorizSign, 0, 0, 0, 0, 1);// break;//case FbxAxisSystem::eZAxis:// mat.set(1, 0, 0, 0, 0, 0, fSign * HorizSign, 0, 0, -fSign, 0, 0, 0, 0, 0, 1);// break;//}// refCoordSysChange = true; }if (refCoordSysChange){osg::Transform* pTransformTemp = model_switch->asTransform();osg::MatrixTransform* pMatrixTransform = pTransformTemp ?pTransformTemp->asMatrixTransform() : NULL;if (pMatrixTransform){pMatrixTransform->setMatrix(pMatrixTransform->getMatrix() * mat);}else{pMatrixTransform = new osg::MatrixTransform(mat);if (isBasicRootNode(*model_switch)){ osg::Group* osgGroup = model_switch->asGroup();for(unsigned int i = 0; i < osgGroup->getNumChildren(); ++i){pMatrixTransform->addChild(osgGroup->getChild(i));}pMatrixTransform->setName(osgGroup->getName());}else{pMatrixTransform->addChild(model_switch);}}//model_switch = pMatrixTransform; }model_switch->setName(filenameInit);return model_switch; }catch (...){OSG_WARN << "Exception thrown while importing \"" << filenameInit << '\"' << std::endl;}return ReadResult::ERROR_IN_READING_FILE; }osgDB::ReaderWriter::WriteResult ReaderWriterIFC::writeNode(const osg::Node& node,const std::string& filename,const Options* options) const {try{shared_ptr<GeometryConverter> geom_converter = m_geometry_converter;shared_ptr<BuildingModel>& model = geom_converter->getBuildingModel();std::wstring m_file_path = StringToWstring(filename);model->initFileHeader(m_file_path);std::stringstream stream;m_step_writer->writeModelToStream(stream, model);FILE * pFile = fopen(filename.c_str(), "wt");if (pFile==nullptr){return false;}fprintf(pFile, "%s", stream.str().c_str());fclose(pFile);return WriteResult::FILE_SAVED;}catch (const std::string& s){return s;}catch (const char* s){return std::string(s);}catch (...){}return WriteResult::ERROR_IN_WRITING_FILE; }/// // Add ourself to the Registry to instantiate the reader/writer. REGISTER_OSGPLUGIN(ifc, ReaderWriterIFC)
对osg库中增加了StatusCallback来和ifcplusplus库中的对应
//StatusCallback //消息回调 #pragma once#include <osg/Export> #include <sstream> #include <iostream> #include <vector>//#include "OpenMPIncludes.h" namespace osg {using namespace std;class OSG_EXPORT StatusCallback{public:typedef void(*Func_call_on_message)(void*, std::string type, std::wstring msg,double v);typedef bool(*Func_call_CancelCheck)(void*);static StatusCallback& getStatusCallback();StatusCallback() = default;virtual ~StatusCallback() = default;void setMessageCallBack(void* obj_ptr, Func_call_on_message func){m_obj_call_on_message = obj_ptr;m_func_call_on_message = func;}void* getMessageCallBack_obj(){return m_obj_call_on_message;}Func_call_on_message getMessageCallBack_func(){return m_func_call_on_message;} virtual void setMessageTarget(StatusCallback* other){m_redirect_target = other;}virtual void unsetMessageCallBack(){m_obj_call_on_message = nullptr;m_func_call_on_message = nullptr;}virtual void setCancelCheck(void* obj_ptr, Func_call_CancelCheck func){m_obj_call_check_cancel = obj_ptr;m_func_check_cancel = func;}virtual void unsetCancelCheck(){m_obj_call_check_cancel = nullptr;m_func_check_cancel = nullptr;}//\brief trigger the callback to pass a message, warning, or error, for example to store in a logfilevirtual void messageCallback( std::string type,std::wstring msg, double v){if (m_redirect_target){m_redirect_target->messageCallback(type, msg, v);return;}if (m_func_call_on_message){if (m_obj_call_on_message){#ifdef ENABLE_OPENMP// Note: this lock protects accesses only for this instance. If several StatusCallback (or derived) objects are bound to the same callback function, a lock is necessary there.ScopedLock lock(m_writelock);#endifm_func_call_on_message(m_obj_call_on_message,type, msg, v);}}}//\brief check if cancellation has been requested.virtual bool isCanceled(){if (m_redirect_target){return m_redirect_target->isCanceled();}if (m_func_check_cancel){if (m_obj_call_check_cancel){#ifdef ENABLE_OPENMP// Note: this lock protects accesses only for this instance. If several StatusCallback (or derived) objects are bound to the same callback function, a lock is necessary there.ScopedLock lock(m_writelock);#endifreturn m_func_check_cancel(m_obj_call_check_cancel);}}return false;}protected://\brief Pointer to the object on which the message callback function is called.void* m_obj_call_on_message = nullptr;//\brief Pointer to the object on which the cancel check function is called.void* m_obj_call_check_cancel = nullptr;//附加的消息回调,在有消息时进行响应,以支持库外使用Func_call_on_message m_func_call_on_message = nullptr;//\brief Pointer to the predicate that determines whether an operation should be canceled.Func_call_CancelCheck m_func_check_cancel = nullptr;StatusCallback* m_redirect_target = nullptr;#ifdef ENABLE_OPENMPMutex m_writelock;#endif}; }
//StatusCallback.cpp #include <osg/StatusCallback> using namespace osg; StatusCallback _StatusCallback; StatusCallback& StatusCallback::getStatusCallback() { return _StatusCallback; }
在使用时添加作为回调
void messageTarget(void* ptr,std::string type, std::wstring msg,double v) {MainWindow* myself = (MainWindow*)ptr;if (myself){ #ifdef ENABLE_OPENMPScopedLock lock(myself->m_mutex_messages); #endifif(v<0)emit myself->TxtOut(QString::fromStdString(type),QString::fromStdWString(msg));else{emit myself->ProgressValue(v,QString::fromStdString(type));}} }
在初始化时调用
osg::StatusCallback& gloableStatus = osg::StatusCallback::getStatusCallback();gloableStatus.setMessageCallBack(this, messageTarget);
ifcplusplus库中也要做相应修改
/* -*-c++-*- IfcQuery www.ifcquery.com * MIT LicenseCopyright (c) 2017 Fabian GeroldPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */#pragma once#include <sstream> #include <iostream> #include <vector> #include "BasicTypes.h" #include "GlobalDefines.h" #include "OpenMPIncludes.h"class BuildingEntity;class IFCQUERY_EXPORT StatusCallback { public:typedef void(*Func_call_on_message)(void*, std::string type, std::wstring msg, double v);enum MessageType{MESSAGE_TYPE_UNKNOWN,MESSAGE_TYPE_GENERAL_MESSAGE,MESSAGE_TYPE_PROGRESS_VALUE, //\brief Progress mechanism to update progress bar or similar.MESSAGE_TYPE_PROGRESS_TEXT, //\brief Progress mechanism to update text in progress bar or similar. MESSAGE_TYPE_MINOR_WARNING,MESSAGE_TYPE_WARNING,MESSAGE_TYPE_ERROR,MESSAGE_TYPE_CLEAR_MESSAGES,MESSAGE_TYPE_CANCELED};/*\class Message\brief Combines all information about a status message, being it a general message, a warning, error, or a notification about a progress (for example during reading of a file).*/class Message{public://\brief Default constructor. Message(){m_message_type = MessageType::MESSAGE_TYPE_UNKNOWN;m_reporting_function = "";m_entity = nullptr;m_progress_value = -1;}std::wstring m_message_text; // Message text.MessageType m_message_type; // Type of message (warning, error etc.).const char* m_reporting_function; // Function name where the message is sent from. You can use the __FUNC__ macro from BuildingException.h.BuildingEntity* m_entity; // IFC entity in case the message applies to a certain entity.double m_progress_value; // Value of progress [0...1]. If negative value is given, the progress itself is ignored, for example when only the progress text is updated.std::string m_progress_type; // Type of progress, for example "parse", "geometry".std::wstring m_progress_text; // A text that describes the current actions. It can be used for example to set a text on the progress bar. };StatusCallback() = default;virtual ~StatusCallback() = default;//\brief error callback mechanism to show messages in guivirtual void setMessageCallBack(void* obj_ptr, void(*func)(void*, shared_ptr<Message> t)){m_obj_call_on_message = obj_ptr;m_func_call_on_message = func;} void setMessageCallBack_extern(void* obj_ptr, Func_call_on_message func){m_obj_call_on_msg_extern = obj_ptr;m_func_call_on_msg_extern = func;}virtual void unsetMessageCallBack_extern(){m_obj_call_on_msg_extern = nullptr;m_func_call_on_msg_extern = nullptr;}virtual void setMessageTarget(StatusCallback* other){m_redirect_target = other;}virtual void unsetMessageCallBack(){m_obj_call_on_message = nullptr;m_func_call_on_message = nullptr;}virtual void setCancelCheck(void* obj_ptr, bool(*func)(void*)){m_obj_call_check_cancel = obj_ptr;m_func_check_cancel = func;}virtual void unsetCancelCheck(){m_obj_call_check_cancel = nullptr;m_func_check_cancel = nullptr;}//\brief trigger the callback to pass a message, warning, or error, for example to store in a logfilevirtual void messageCallback(shared_ptr<Message> m){if (m_redirect_target){m_redirect_target->messageCallback(m);return;}#ifdef _DEBUGif (!m_func_call_on_message || !m_obj_call_on_message){if (m){switch (m->m_message_type){case MESSAGE_TYPE_UNKNOWN:case MESSAGE_TYPE_GENERAL_MESSAGE:case MESSAGE_TYPE_MINOR_WARNING:case MESSAGE_TYPE_WARNING:case MESSAGE_TYPE_ERROR:std::wcout << L"messageCallback not set. Lost message: " << m->m_message_text.c_str() << std::endl;break;}}}if (m->m_message_type == MESSAGE_TYPE_ERROR){std::wcout << L"error: " << m->m_message_text.c_str() << std::endl;} #endifif (m_func_call_on_message){if (m_obj_call_on_message){ #ifdef ENABLE_OPENMP// Note: this lock protects accesses only for this instance. If several StatusCallback (or derived) objects are bound to the same callback function, a lock is necessary there.ScopedLock lock(m_writelock); #endifm_func_call_on_message(m_obj_call_on_message, m);}}if (m_func_call_on_msg_extern){if (m_obj_call_on_msg_extern){ #ifdef ENABLE_OPENMP// Note: this lock protects accesses only for this instance. If several StatusCallback (or derived) objects are bound to the same callback function, a lock is necessary there.ScopedLock lock(m_writelock); #endifstd::string msgType;switch (m->m_message_type){case MESSAGE_TYPE_UNKNOWN:msgType = "UNKNOWN";break;case MESSAGE_TYPE_GENERAL_MESSAGE:msgType = "GENERAL_MESSAGE";break;case MESSAGE_TYPE_PROGRESS_VALUE:msgType = "PROGRESS_VALUE";break;case MESSAGE_TYPE_PROGRESS_TEXT:msgType = "PROGRESS_TEXT";break;case MESSAGE_TYPE_MINOR_WARNING:msgType = "MINOR_WARNING";break;case MESSAGE_TYPE_WARNING:msgType = "WARNING";break;case MESSAGE_TYPE_ERROR:msgType = "ERROR";break;}if(m->m_progress_value>=0)m_func_call_on_msg_extern(m_obj_call_on_msg_extern, m->m_progress_type, m->m_progress_text,m->m_progress_value);elsem_func_call_on_msg_extern(m_obj_call_on_msg_extern, msgType, m->m_message_text, m->m_progress_value);}}}//\brief check if cancellation has been requested.virtual bool isCanceled(){if (m_redirect_target){return m_redirect_target->isCanceled();}if (m_func_check_cancel){if (m_obj_call_check_cancel){ #ifdef ENABLE_OPENMP// Note: this lock protects accesses only for this instance. If several StatusCallback (or derived) objects are bound to the same callback function, a lock is necessary there.ScopedLock lock(m_writelock); #endifreturn m_func_check_cancel(m_obj_call_check_cancel);}}return false;}virtual void messageCallback(const std::string& message_text, MessageType type, const char* reporting_function, BuildingEntity* entity = nullptr){shared_ptr<Message> message(new Message());message->m_message_text.assign(message_text.begin(), message_text.end());message->m_message_type = type;message->m_reporting_function = reporting_function;message->m_entity = entity;messageCallback(message);}virtual void messageCallback(const std::wstring& message_text, MessageType type, const char* reporting_function, BuildingEntity* entity = nullptr){shared_ptr<Message> message(new Message());message->m_message_text.assign(message_text);message->m_message_type = type;message->m_reporting_function = reporting_function;message->m_entity = entity;messageCallback(message);}virtual void progressValueCallback(double progress_value, const std::string& progress_type){shared_ptr<Message> progress_message(new Message());progress_message->m_message_type = MessageType::MESSAGE_TYPE_PROGRESS_VALUE;progress_message->m_progress_value = progress_value;progress_message->m_progress_type.assign(progress_type);messageCallback(progress_message);}virtual void progressTextCallback(const std::wstring& progress_text){shared_ptr<Message> progress_message(new Message());progress_message->m_message_type = MessageType::MESSAGE_TYPE_PROGRESS_TEXT;progress_message->m_progress_value = 0;progress_message->m_progress_text.assign(progress_text);messageCallback(progress_message);}virtual void clearMessagesCallback(){shared_ptr<Message> progress_message(new Message());progress_message->m_message_type = MessageType::MESSAGE_TYPE_CLEAR_MESSAGES;messageCallback(progress_message);}virtual void canceledCallback(){shared_ptr<Message> canceled_message(new Message());canceled_message->m_message_type = MessageType::MESSAGE_TYPE_CANCELED;messageCallback(canceled_message);}protected://\brief Pointer to the object on which the message callback function is called.void* m_obj_call_on_message = nullptr;void* m_obj_call_on_msg_extern = nullptr;//\brief Pointer to the object on which the cancel check function is called.void* m_obj_call_check_cancel = nullptr;//\brief Pointer to the callback function for messages.void(*m_func_call_on_message)(void*, shared_ptr<Message> t) = nullptr;//附加的消息回调,在有消息时进行响应,以支持库外使用Func_call_on_message m_func_call_on_msg_extern = nullptr;//\brief Pointer to the predicate that determines whether an operation should be canceled.bool(*m_func_check_cancel)(void*) = nullptr;StatusCallback* m_redirect_target = nullptr;#ifdef ENABLE_OPENMPMutex m_writelock; #endif };
==========================================================