C++ and OpenVDB FloatGrid to Vec3SGrid and back to FloatGrid - c++

Here is a basic sample converting them and dumping the result into a mesh:
// FloatGrid to Vec3SGrid
openvdb::Vec3SGrid::Ptr Vec3SGrid = openvdb::Vec3SGrid::create();
Vec3SGrid->setTransform( floatGridA->transformPtr());
Vec3SGrid->tree().root().setBackground(openvdb::Vec3f(floatGridA->background()),true);
for (auto itAll = floatGridA ->cbeginValueOn(); itAll; ++itAll) {
auto pos = itAll.getCoord();
auto valueAll = itAll.getValue();
auto Vec3s = Vec3SGrid->tree().getValue(pos);
Vec3s[0] = valueAll;
Vec3SGrid->tree().setValue(pos, Vec3s);
}
// Back to FloatGrid
openvdb::FloatGrid::Ptr floatGridB = openvdb::FloatGrid::create();
floatGridB->setTransform( Vec3SGrid->transformPtr());
floatGridB->tree().root().setBackground(Vec3SGrid->background()[0], true);
for (auto it = grid->cbeginValueOn(); it; ++it) {
auto pos = it.getCoord();
auto Vec3s = it.getValue();
floatGridB->tree().setValue(pos, Vec3s[0]);
}
OpenVDBMesh meshA, meshB;
openvdb::tools::volumeToMesh(*floatGridA , meshA.points, meshA.faces, meshA.quads, iso, adapt, flag_relax);
openvdb::tools::volumeToMesh(*floatGridB , meshB.points, meshB.faces, meshB.quads, iso, adapt, flag_relax);
Unfortunately the besides I've copied transform too, the result on both meshes are different.
Any idea on that? thank you!

Related

open62541 client fails when calling method with custom datatype input argument

I'm using open62541 to connect to an OPC/UA server and I'm trying to call methods that a certain object on that server provides. Those methods have custom types as input arguments; for example, the following method takes a structure of three booleans:
<opc:Method SymbolicName="SetStatusMethodType" ModellingRule="Mandatory">
<opc:InputArguments>
<opc:Argument Name="Status" DataType="VisionStatusDataType" ValueRank="Scalar"/>
</opc:InputArguments>
<opc:OutputArguments />
</opc:Method>
Here, VisionStatusDataType is the following structure:
<opc:DataType SymbolicName="VisionStatusDataType" BaseType="ua:Structure">
<opc:ClassName>VisionStatus</opc:ClassName>
<opc:Fields>
<opc:Field Name="Camera" DataType="ua:Boolean" ValueRank="Scalar"/>
<opc:Field Name="StrobeController" DataType="ua:Boolean" ValueRank="Scalar"/>
<opc:Field Name="Server" DataType="ua:Boolean" ValueRank="Scalar"/>
</opc:Fields>
</opc:DataType>
Now, when calling the method, I'm encoding the data into an UA_ExtensionObject, and wrap that one as an UA_Variant to provide it to UA_Client_call. The encoding looks like this:
void encode(const QVariantList& vecqVar, size_t& nIdx, const DataType& dt, std::back_insert_iterator<std::vector<UAptr<UA_ByteString>>> itOut)
{
if (dt.isSimple())
{
auto&& qVar = vecqVar.at(nIdx++);
auto&& uaVar = convertToUaVar(qVar, dt.uaType());
auto pOutBuf = create<UA_ByteString>();
auto nStatus = UA_encodeBinary(uaVar.data, dt.uaType(), pOutBuf.get());
statusCheck(nStatus);
itOut = std::move(pOutBuf);
}
else
{
for (auto&& dtMember : dt.members())
encode(vecqVar, nIdx, dtMember, itOut);
}
}
UA_Variant ToUAVariant(const QVariant& qVar, const DataType& dt)
{
if (dt.isSimple())
return convertToUaVar(qVar, dt.uaType());
else
{
std::vector<UAptr<UA_ByteString>> vecByteStr;
auto&& qVarList = qVar.toList();
size_t nIdx = 0UL;
encode(qVarList, nIdx, dt, std::back_inserter(vecByteStr));
auto pExtObj = UA_ExtensionObject_new();
pExtObj->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
auto nSizeAll = std::accumulate(vecByteStr.cbegin(), vecByteStr.cend(), 0ULL, [](size_t nSize, const UAptr<UA_ByteString>& pByteStr) {
return nSize + pByteStr->length;
});
auto&& uaEncoded = pExtObj->content.encoded;
uaEncoded.typeId = dt.uaType()->typeId;
uaEncoded.body.length = nSizeAll;
auto pData = uaEncoded.body.data = new UA_Byte[nSizeAll];
nIdx = 0UL;
for (auto&& pByteStr : vecByteStr)
{
memcpy_s(pData + nIdx, nSizeAll - nIdx, pByteStr->data, pByteStr->length);
nIdx += pByteStr->length;
}
UA_Variant uaVar;
UA_Variant_init(&uaVar);
UA_Variant_setScalar(&uaVar, pExtObj, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
return uaVar;
}
}
The DataType class is a wrapper for the UA_DataType structure; the original open62541 type can be accessed via DataType::uaType().
Now, once a have the variant (containing the extension object), the method call looks like this:
auto uavarInput = ToUAVariant(qvarArg, dtInput);
UA_Variant* pvarOut;
size_t nOutSize = 0UL;
auto nStatus = UA_Client_call(m_pClient, objNode.nodeId(), m_uaNodeId, 1UL, &uavarInput, &nOutSize, &pvarOut);
The status is 2158690304, i.e. BadInvalidArgument according to UA_StatusCode_name.
Is there really something wrong with the method argument? Are we supposed to send ExtensionObjects, or what data type should the variant contain?
Is it possible that the server itself (created using the .NET OPC/UA stack) is not configured correctly?
N.B., the types here are custom types; that is, the encoding is done manually (see above) by storing the byte representation of all members next to each other in an UA_ByteString - just the opposite of what I'm doing when reading variables or output arguments, which works just fine.
The problem is the typeId of the encoded object. For the server in order to understand the received data, it needs to know the NodeId of the encoding, not the actual NodeId of the type itself. That encoding can be found by following the HasEncoding reference (named "Default Binary") of the type:
auto pRequest = create<UA_BrowseRequest>();
auto pDescr = pRequest->nodesToBrowse = UA_BrowseDescription_new();
pRequest->nodesToBrowseSize = 1UL;
pDescr->nodeId = m_uaNodeId;
pDescr->resultMask = UA_BROWSERESULTMASK_ALL;
pDescr->browseDirection = UA_BROWSEDIRECTION_BOTH;
pDescr->referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASENCODING);
auto response = UA_Client_Service_browse(m_pClient, *pRequest);
for (auto k = 0UL; k < response.resultsSize; ++k)
{
auto browseRes = response.results[k];
for (auto n = 0UL; n < browseRes.referencesSize; ++n)
{
auto browseRef = browseRes.references[n];
if (ToQString(browseRef.browseName.name).contains("Binary"))
{
m_nodeBinaryEnc = browseRef.nodeId.nodeId;
break;
}
}
}
Once you have that NodeId, you pass it to UA_ExtensionObject::content::encoded::typeId:
auto pExtObj = UA_ExtensionObject_new();
pExtObj->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
auto nSizeAll = std::accumulate(vecByteStr.cbegin(), vecByteStr.cend(), 0ULL, [](size_t nSize, const UAptr<UA_ByteString>& pByteStr) {
return nSize + pByteStr->length;
});
auto&& uaEncoded = pExtObj->content.encoded;
uaEncoded.typeId = dt.encoding();
uaEncoded.body.length = nSizeAll;
auto pData = uaEncoded.body.data = new UA_Byte[nSizeAll];
nIdx = 0UL;
for (auto&& pByteStr : vecByteStr)
{
memcpy_s(pData + nIdx, nSizeAll - nIdx, pByteStr->data, pByteStr->length);
nIdx += pByteStr->length;
}

Vulkan validation errors states my images are in the wrong layout, but only the two first times I present images from the swapchain

I have loosely been following this guide to setup some simple rendering in Vulkan using the raii headers in Vulkan-Hpp. I have skipped the Graphics Pipeline Basics section (except for the render pass chapter) just to see if I'm able to only get the render pass working and presenting images from the swapchain.
I am now at the point where I can clear the current swapchain image to a certain color and present it. However, this fails for the first two frames that I try to present, and after that it runs smoothly without any validation errors. I am completely stumped at why this is happening, so I'm just gonna give the details of what I know and what I have tried and hopefully someone might know the answer here.
The error I get for the first two frames is as follows:
Validation Error: [ VUID-VkPresentInfoKHR-pImageIndices-01296 ] Object 0: handle = 0x1f5d50ee1e0, type = VK_OBJECT_TYPE_QUEUE; | MessageID = 0xc7aabc16 | vkQueuePresentKHR(): pSwapchains[0] images passed to present must be in layout VK_IMAGE_LAYOUT_PRESENT_SRC_KHR or VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR but is in VK_IMAGE_LAYOUT_UNDEFINED. The Vulkan spec states: Each element of pImageIndices must be the index of a presentable image acquired from the swapchain specified by the corresponding element of the pSwapchains array, and the presented image subresource must be in the VK_IMAGE_LAYOUT_PRESENT_SRC_KHR layout at the time the operation is executed on a VkDevice (https://github.com/KhronosGroup/Vulkan-Docs/search?q=)VUID-VkPresentInfoKHR-pImageIndices-01296)
This makes it seem like there might be a synchronization issue for the first two frames or something. Since I'm still doing early testing with Vulkan I'm just using device.waitIdle() instead of proper synchronization with semaphores and fences. I know that usage of waitIdle is a slow solution, but I thought it would at least serve to keep things synchronized, so I'm not sure if it is a synchronization issue.
My swapchain has 3 images, so if it was a problem with presenting images in the first round through the images then I should have gotten three errors...
The presentKHR function returns vk::Result::Success even on the first two frames. I have also tried turning off validation layers, and when I do so the first two frames are able to be presented, so it might be a bug in the validation layers?
Some of my initialization code:
// After swapchain creation
auto images = m_swapchain.getImages();
for (auto& image : images) {
m_images.emplace(image, createImageView(image));
}
m_renderPass = createRenderPass();
m_frameBuffers.reserve(m_images.size());
for (auto& [image, imageView] : m_images) {
m_frameBuffers.push_back(createFrameBuffer(imageView));
}
auto [result, imageIndex] = m_swapchain.acquireNextImage(
std::numeric_limits<uint64_t>().max(),
*m_imageAvailableSemaphore
);
// I use a semaphore here because the Vulkan spec states that I must use a semaphore or fence here
m_imageIndex = imageIndex;
// Functions called above
vk::raii::ImageView Swapchain::createImageView(const vk::Image& image) const {
try {
return m_context.getDevice().createImageView(
vk::ImageViewCreateInfo{
.flags = {},
.image = image,
.viewType = vk::ImageViewType::e2D,
.format = m_surfaceFormat.format,
.components = vk::ComponentMapping{
.r = vk::ComponentSwizzle::eIdentity,
.g = vk::ComponentSwizzle::eIdentity,
.b = vk::ComponentSwizzle::eIdentity,
.a = vk::ComponentSwizzle::eIdentity
},
.subresourceRange = vk::ImageSubresourceRange{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1
}
}
);
}
catch (const std::exception& e) {
// Error handling...
}
}
vk::raii::RenderPass Swapchain::createRenderPass() const {
auto attachments = std::array{
vk::AttachmentDescription{
.flags = {},
.format = m_surfaceFormat.format,
.samples = vk::SampleCountFlagBits::e1,
.loadOp = vk::AttachmentLoadOp::eClear,
.storeOp = vk::AttachmentStoreOp::eStore,
.stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
.stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
.initialLayout = vk::ImageLayout::eUndefined,
.finalLayout = vk::ImageLayout::ePresentSrcKHR
}
};
auto attachmentReferences = std::array{
vk::AttachmentReference{
.attachment = 0,
.layout = vk::ImageLayout::eColorAttachmentOptimal
}
};
auto subpasses = std::array{
vk::SubpassDescription{
.flags = {},
.pipelineBindPoint = vk::PipelineBindPoint::eGraphics,
.inputAttachmentCount = 0,
.pInputAttachments = nullptr,
.colorAttachmentCount = static_cast<uint32_t>(attachmentReferences.size()),
.pColorAttachments = attachmentReferences.data(),
.pResolveAttachments = nullptr,
.pDepthStencilAttachment = nullptr,
.preserveAttachmentCount = 0,
.pPreserveAttachments = nullptr
}
};
try {
return m_context.getDevice().createRenderPass(
vk::RenderPassCreateInfo{
.flags = {},
.attachmentCount = static_cast<uint32_t>(attachments.size()),
.pAttachments = attachments.data(),
.subpassCount = static_cast<uint32_t>(subpasses.size()),
.pSubpasses = subpasses.data(),
.dependencyCount = 0,
.pDependencies = nullptr
}
);
}
catch (const std::exception& e) {
// Error handling...
}
}
vk::raii::Framebuffer Swapchain::createFrameBuffer(const vk::raii::ImageView& imageView) const {
try {
return m_context.getDevice().createFramebuffer(
vk::FramebufferCreateInfo{
.flags = {},
.renderPass = *m_renderPass,
.attachmentCount = 1,
.pAttachments = &*imageView,
.width = m_imageExtent.width,
.height = m_imageExtent.height,
.layers = 1
}
);
}
catch (const std::exception& e) {
// Error handling...
}
}
Rendering code executed every frame:
// The actual render function called every frame
void Renderer::render() {
m_context->recordCommands(
[&]() {
m_swapchain->beginRenderPassCommand(0.125f, 0.125f, 0.125f);
m_swapchain->endRenderPassCommand();
}
);
m_context->submitRecording();
m_swapchain->swap();
}
void GraphicsContext::recordCommands(const Application::Recording& recording) {
m_device.waitIdle();
m_commandBuffer.reset();
m_commandBuffer.begin(
vk::CommandBufferBeginInfo{
.flags = {},
.pInheritanceInfo = {}
}
);
recording();
m_commandBuffer.end();
}
void Swapchain::beginRenderPassCommand(
float clearColorRed,
float clearColorGreen,
float clearColorBlue
) {
auto clearValues = std::array{
vk::ClearValue(
vk::ClearColorValue(
std::array{
clearColorRed,
clearColorGreen,
clearColorBlue,
1.0f
}
)
)
};
m_context.getCommandBuffer().beginRenderPass(
vk::RenderPassBeginInfo{
.renderPass = *m_renderPass,
.framebuffer = *m_frameBuffers[m_imageIndex],
.renderArea = vk::Rect2D{
.offset = vk::Offset2D{
.x = 0,
.y = 0
},
.extent = m_imageExtent
},
.clearValueCount = static_cast<uint32_t>(clearValues.size()),
.pClearValues = clearValues.data()
},
vk::SubpassContents::eInline
);
}
void Swapchain::endRenderPassCommand() {
m_context.getCommandBuffer().endRenderPass();
}
void GraphicsContext::submitRecording() {
m_device.waitIdle();
m_graphicsQueue.submit(
vk::SubmitInfo{
.waitSemaphoreCount = 0,
.pWaitSemaphores = nullptr,
.pWaitDstStageMask = nullptr,
.commandBufferCount = 1,
.pCommandBuffers = &*m_commandBuffer,
.signalSemaphoreCount = 0,
.pSignalSemaphores = nullptr
}
);
}
void Swapchain::swap() {
m_context.getDevice().waitIdle();
auto presentResult = m_context.getPresentQueue().presentKHR(
vk::PresentInfoKHR{
.waitSemaphoreCount = 0,
.pWaitSemaphores = nullptr,
.swapchainCount = 1,
.pSwapchains = &*m_swapchain,
.pImageIndices = &m_imageIndex,
.pResults = nullptr
}
);
m_context.getDevice().waitIdle();
auto [result, imageIndex] = m_swapchain.acquireNextImage(
std::numeric_limits<uint64_t>().max(),
*m_imageAvailableSemaphore
);
m_imageIndex = imageIndex;
}
Outside of specific circumstances or explicit synchronization, operations on the GPU execute in an arbitrary order.
Your graphics submission and your queue presentation have no synchronization between them. Therefore, they can execute in whatever order the implementation wants regardless of when you issue them.
However, since the graphics operation acts on an object which the presentation operation uses, there is a de-facto dependency. The graphics operation must act first. But you have no actual synchronization to enforce that dependency.
Hence the validation errors. You need to ensure that the queue presentation happens after the rendering operation.
I have now gotten confirmation that this issue is caused by a bug in the validation layers.
Here's the issue on Github: https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/4422

TDLib: how to send bold text in the message? (ะก++)

Using the official TDLib C++ example, I'm trying to send a message with formatted markdown text.
Here's my code:
auto send_message = td_api::make_object<td_api::sendMessage>();
send_message->chat_id_ = -1001424068198;
auto message_content = td_api::make_object<td_api::inputMessageText>();
std::string text = "Hello! **how are u?**";
message_content->text_ = td_api::make_object<td_api::formattedText>();
message_content->text_->text_ = std::move(text);
send_message->input_message_content_ = std::move(message_content);
send_query(std::move(send_message), {});
I expect to see "Hello! how are u?" but the message comes as it is written in the code, without markdown formatting applied.
I spent hours on google trying to figure out how to force TDLib to parse it.
UPDATE: SOLVED!
Thanks Azeem for help!
Using this example, the following code should send the parsed message (tested in VS 2019)
void sendMsg(INT64 chatID, INT64 ReplyTo, const char* textMsg) {
const std::string text = textMsg;
auto textParseMarkdown = td_api::make_object<td_api::textParseModeMarkdown>(2);
auto parseTextEntities = td_api::make_object<td_api::parseTextEntities>(text, std::move(textParseMarkdown));
td::Client::Request parseRequest{ 123, std::move(parseTextEntities) };
auto parseResponse = td::Client::execute(std::move(parseRequest));
if (parseResponse.object->get_id() == td_api::formattedText::ID) {
auto formattedText = td_api::make_object<td_api::formattedText>();
formattedText = td_api::move_object_as<td_api::formattedText>(parseResponse.object);
auto send_message = td_api::make_object<td_api::sendMessage>();
send_message->chat_id_ = chatID;
auto message_content = td_api::make_object<td_api::inputMessageText>();
message_content->text_ = std::move(formattedText);
send_message->input_message_content_ = std::move(message_content);
send_message->reply_to_message_id_ = ReplyTo;
send_query(std::move(send_message), {});
}
}
You can use td_api::textParseModeMarkdown, td_api::parseTextEntities and td::Client::execute() like this:
using namespace td;
const std::string text = "*bold* _italic_ `code`";
auto textParseMarkdown = td_api::make_object<td_api::textParseModeMarkdown>( 2 );
auto parseTextEntities = td_api::make_object<td_api::parseTextEntities>( text, std::move( textParseMarkdown ) );
td::Client::Request parseRequest { 123, std::move( parseTextEntities ) };
auto parseResponse = td::Client::execute( std::move( parseRequest ) );
auto formattedText = td_api::make_object<td_api::formattedText>();
if ( parseResponse.object->get_id() == td_api::formattedText::ID )
{
formattedText = td_api::move_object_as<td_api::formattedText>( parseResponse.object );
}
else
{
std::vector<td_api::object_ptr<td_api::textEntity>> entities;
formattedText = td_api::make_object<td_api::formattedText>( text, std::move(entities) );
}
std::cout << td_api::to_string( formattedText ) << '\n';
For debugging purposes, you can use td_api::to_string() to dump the contents of an object. For example, dumping parseTextEntities like this:
std::cout << td_api::to_string( parseTextEntities ) << '\n';
would give this:
parseTextEntities {
text = "*bold* _italic_ `code`"
parse_mode = textParseModeMarkdown {
version = 2
}
}

C++11/ Auto assign me a bool?

TGuildMemberContainer::iterator it;
if ((it = m_member.find (p->dwPID)) == m_member.end())
{
m_member.insert (std::make_pair (p->dwPID, TGuildMember (p->dwPID, p->bGrade, p->isGeneral, p->bJob, p->bLevel, p->dwOffer, p->szName)));
}
else
{
TGuildMember& r_gm = it->second;
r_gm.pid = p->dwPID;
r_gm.grade = p->bGrade;
r_gm.job = p->bJob;
r_gm.offer_exp = p->dwOffer;
r_gm.is_general = p->isGeneral;
}
Hi, i want to apply auto transform intro my codes, but i'm stuck.
If i add auto
if (auto it = m_member.find (p->dwPID) == m_member.end())
The auto assign a bool
if ( bool it = m_member.find (p->dwPID) == m_member.end())
This say Visual Studio intelisense.
My question, why auto assign me a bool and not the corect iteration range ?
Because the compiler is parsing it as:
if (auto it = (m_member.find (p->dwPID) == m_member.end()))
which is a boolean expression. You can't write it as:
if ((auto it = m_member.find (p->dwPID)) == m_member.end())
because putting the variable declaration inside brackets like that is not allowed.
I find creating variables in if hard to read. Just use:
const auto it = m_member.find(p->dwPID);
if (it == m_member.end())
...
In C++17, this can be done as
if (auto it = m_member.find (p->dwPID); it == m_member.end())
which avoids the scope problem mentioned in the other answer.

How to convert C++ 11 loop in to traditional loop?

I am having this error in my program error C2143: syntax error : missing ',' before ':', I am using Visual c++ express 2010 and i think C++11 dosent support in VC 2010.
Can somone please modify this code and explain how to revert this for loop in traditional for loop ? ouFlexSignalInfo is a list data type from c++ stl
for(auto ouSignalInfo : ouFlexSignalInfo) //C++11;
{
SSignalInfo ouSignal;
ouSignal.m_omEnggValue = ouSignalInfo.m_omEnggValue.c_str();
ouSignal.m_omRawValue = ouSignalInfo.m_omRawValue.c_str();
ouSignal.m_omSigName = ouSignalInfo.m_omSigName.c_str();
ouSignal.m_omUnit = ouSignalInfo.m_omUnit.c_str();
ouSignal.m_msgName=ouFrame.m_strFrameName.c_str();
SigInfoArray.Add(ouSignal);
}
it is roughly equivalent to:
auto iterBegin = std::begin(ouFlexSignalInfo);
auto iterEnd = std::end(ouFlexSignalInfo);
for(; iterBegin != iterEnd; ++iterBegin)
{
auto ouSignalInfo = *iterBegin;
//the rest of body
}
the iterBegin and iterEnd are iterators returned from the ouFlexSignalInfo members begin and end.
This kind of loop works for everything that has begin and end members
If you use MS VC++ 2010 then the compiler supports a MS language extension for the range-based for loop. The code will look the following way
for each ( auto ouSignalInfo in ouFlexSignalInfo )
{
SSignalInfo ouSignal;
ouSignal.m_omEnggValue = ouSignalInfo.m_omEnggValue.c_str();
ouSignal.m_omRawValue = ouSignalInfo.m_omRawValue.c_str();
ouSignal.m_omSigName = ouSignalInfo.m_omSigName.c_str();
ouSignal.m_omUnit = ouSignalInfo.m_omUnit.c_str();
ouSignal.m_msgName=ouFrame.m_strFrameName.c_str();
SigInfoArray.Add(ouSignal);
}
Or it would be better to write
for each ( const auto &ouSignalInfo in ouFlexSignalInfo )
{
SSignalInfo ouSignal;
ouSignal.m_omEnggValue = ouSignalInfo.m_omEnggValue.c_str();
ouSignal.m_omRawValue = ouSignalInfo.m_omRawValue.c_str();
ouSignal.m_omSigName = ouSignalInfo.m_omSigName.c_str();
ouSignal.m_omUnit = ouSignalInfo.m_omUnit.c_str();
ouSignal.m_msgName=ouFrame.m_strFrameName.c_str();
SigInfoArray.Add(ouSignal);
}
As the type of ouFlexSignalInfo is unknown then you can use iterators. For example
#include <iterator>
for ( auto it = std::begin( ouFlexSignalInfo ); it != std::end( ouFlexSignalInfo ); ++it )
{
SSignalInfo ouSignal;
ouSignal.m_omEnggValue = it->m_omEnggValue.c_str();
ouSignal.m_omRawValue = it->m_omRawValue.c_str();
ouSignal.m_omSigName = it->m_omSigName.c_str();
ouSignal.m_omUnit = it->m_omUnit.c_str();
ouSignal.m_msgName = ouFrame.m_strFrameName.c_str();
SigInfoArray.Add( ouSignal );
}