osg的IFC插件
ifc是一种重要的建筑行业发布的建筑产品数据表达标准,搜索发现osg没有相应的插件。
找到了一个C++库ifcplusplus。该库的例子中对数据结构进行到osg的转换,发现可以经过修改,改造成osg的插件。
- 插件部分
//ReaderWriterIFC.h
#ifndef READERWRITERIFC_H
#define READERWRITERIFC_H
#include <osgDB/ReaderWriter>
///
// OSG reader plugin for the ".ifc" format.
//
// This plugin requires the ifcplusplus
class 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 nodes
return 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 transform
return 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 transform
return false;
}
}
else
{
// Other transform (not identity or not predefined type)
return false;
}
}
// Test the presence of a non-empty stateset
if (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转wstring
unsigned 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 scenegraph
osg::ref_ptr<osg::Switch> model_switch = m_sw_model; SceneGraphUtils::clearAllChildNodes(model_switch);
// reset the IFC model
shared_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 model
std::wstring fileName = StringToWstring(filenameInit);
m_step_reader->loadModelFromFile(fileName, geometry_converter->getBuildingModel());
// convert IFC geometric representations into Carve geometry
const 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 OSG
shared_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 structure
const 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 origin
const 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)
2. 消息响应部分
为了能够使读取过程的消息和进度能够在应用中获取,对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 logfile
virtual 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);
#endif
m_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);
#endif
return 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_OPENMP
Mutex 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_OPENMP
ScopedLock lock(myself->m_mutex_messages);
#endif
if(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 License
Copyright (c) 2017 Fabian Gerold
Permission 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 gui
virtual 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 logfile
virtual void messageCallback(shared_ptr<Message> m)
{
if (m_redirect_target)
{
m_redirect_target->messageCallback(m);
return;
}
#ifdef _DEBUG
if (!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;
}
#endif
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);
#endif
m_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);
#endif
std::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);
else
m_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);
#endif
return 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_OPENMP
Mutex m_writelock;
#endif
};