#3561 HoloLens: Establish sharing server session and publish visualization data to sharing server

This commit is contained in:
sigurdp 2018-10-25 15:34:21 +02:00
parent 23d6e8ee2a
commit 8ca73960f4
18 changed files with 1486 additions and 408 deletions

View File

@ -34,7 +34,7 @@
#include "RicImportInputEclipseCaseFeature.h"
#include "RicImportSummaryCasesFeature.h"
#include "ExportCommands/RicSnapshotAllViewsToFileFeature.h"
#include "HoloLensCommands/RicHoloLensSession.h"
#include "HoloLensCommands/RicHoloLensSessionManager.h"
#include "Rim2dIntersectionViewCollection.h"
#include "RimCellRangeFilterCollection.h"
@ -996,8 +996,8 @@ bool RiaApplication::saveProjectAs(const QString& fileName)
//--------------------------------------------------------------------------------------------------
void RiaApplication::closeProject()
{
RicHoloLensSession::instance()->terminateSession();
RicHoloLensSession::refreshToolbarState();
RicHoloLensSessionManager::instance()->terminateSession();
RicHoloLensSessionManager::refreshToolbarState();
RiuMainWindow* mainWnd = RiuMainWindow::instance();

View File

@ -6,14 +6,18 @@ ${CMAKE_CURRENT_LIST_DIR}/RicHoloLensExportImpl.h
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensExportToSharingServerFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensCreateSessionFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensTerminateSessionFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensRestClient.h
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensServerSettings.h
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensCreateSessionUi.h
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensSession.h
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensSessionManager.h
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensCreateDummyFileBackedSessionFeature.h
${CMAKE_CURRENT_LIST_DIR}/VdeArrayDataPacket.h
${CMAKE_CURRENT_LIST_DIR}/VdeExportPart.h
${CMAKE_CURRENT_LIST_DIR}/VdeFileExporter.h
${CMAKE_CURRENT_LIST_DIR}/VdePacketDirectory.h
${CMAKE_CURRENT_LIST_DIR}/VdeVizDataExtractor.h
)
set (SOURCE_GROUP_SOURCE_FILES
@ -23,14 +27,18 @@ ${CMAKE_CURRENT_LIST_DIR}/RicHoloLensExportToFolderUi.cpp
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensExportToSharingServerFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensCreateSessionFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensTerminateSessionFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensRestClient.cpp
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensServerSettings.cpp
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensCreateSessionUi.cpp
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensSession.cpp
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensSessionManager.cpp
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensCreateDummyFileBackedSessionFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/VdeArrayDataPacket.cpp
${CMAKE_CURRENT_LIST_DIR}/VdeExportPart.cpp
${CMAKE_CURRENT_LIST_DIR}/VdeFileExporter.cpp
${CMAKE_CURRENT_LIST_DIR}/VdePacketDirectory.cpp
${CMAKE_CURRENT_LIST_DIR}/VdeVizDataExtractor.cpp
)
@ -42,4 +50,11 @@ list(APPEND CODE_SOURCE_FILES
${SOURCE_GROUP_SOURCE_FILES}
)
set (QT_MOC_HEADERS
${QT_MOC_HEADERS}
${CMAKE_CURRENT_LIST_DIR}/RicHoloLensRestClient.h
)
source_group( "CommandFeature\\HoloLens" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake )

View File

@ -18,7 +18,7 @@
#include "RicHoloLensCreateDummyFileBackedSessionFeature.h"
#include "RicHoloLensSession.h"
#include "RicHoloLensSessionManager.h"
#include "RiaQIconTools.h"
@ -31,7 +31,7 @@ CAF_CMD_SOURCE_INIT(RicHoloLensCreateDummyFiledBackedSessionFeature, "RicHoloLen
//--------------------------------------------------------------------------------------------------
bool RicHoloLensCreateDummyFiledBackedSessionFeature::isCommandEnabled()
{
return !RicHoloLensSession::instance()->isSessionValid();
return RicHoloLensSessionManager::instance()->session() ? false : true;
}
//--------------------------------------------------------------------------------------------------
@ -39,9 +39,9 @@ bool RicHoloLensCreateDummyFiledBackedSessionFeature::isCommandEnabled()
//--------------------------------------------------------------------------------------------------
void RicHoloLensCreateDummyFiledBackedSessionFeature::onActionTriggered(bool isChecked)
{
RicHoloLensSession::instance()->createDummyFileBackedSession();
RicHoloLensSessionManager::instance()->createDummyFileBackedSession();
RicHoloLensSession::refreshToolbarState();
RicHoloLensSessionManager::refreshToolbarState();
}
//--------------------------------------------------------------------------------------------------

View File

@ -22,7 +22,7 @@
#include "RicHoloLensCreateSessionUi.h"
#include "RicHoloLensServerSettings.h"
#include "RicHoloLensSession.h"
#include "RicHoloLensSessionManager.h"
#include "cafPdmSettings.h"
#include "cafPdmUiPropertyViewDialog.h"
@ -37,7 +37,7 @@ CAF_CMD_SOURCE_INIT(RicHoloLensCreateSessionFeature, "RicHoloLensCreateSessionFe
//--------------------------------------------------------------------------------------------------
bool RicHoloLensCreateSessionFeature::isCommandEnabled()
{
return !RicHoloLensSession::instance()->isSessionValid();
return RicHoloLensSessionManager::instance()->session() ? false : true;
}
//--------------------------------------------------------------------------------------------------
@ -60,10 +60,10 @@ void RicHoloLensCreateSessionFeature::onActionTriggered(bool isChecked)
propertyDialog.exec();
RicHoloLensSession::instance()->createSession(
RicHoloLensSessionManager::instance()->createSession(
createSessionUi.serverUrl(), createSessionUi.sessionName(), createSessionUi.sessionPinCode());
RicHoloLensSession::refreshToolbarState();
RicHoloLensSessionManager::refreshToolbarState();
}

View File

@ -17,13 +17,12 @@
/////////////////////////////////////////////////////////////////////////////////
#include "RicHoloLensExportToSharingServerFeature.h"
#include "RicHoloLensSessionManager.h"
#include "RicHoloLensSession.h"
#include "VdeFileExporter.h"
#include "RiaApplication.h"
#include "RiaQIconTools.h"
#include "RiaLogging.h"
#include "RimGridView.h"
@ -36,7 +35,15 @@ CAF_CMD_SOURCE_INIT(RicHoloLensExportToSharingServerFeature, "RicHoloLensExportT
//--------------------------------------------------------------------------------------------------
bool RicHoloLensExportToSharingServerFeature::isCommandEnabled()
{
return RicHoloLensSession::instance()->isSessionValid();
RicHoloLensSession* session = RicHoloLensSessionManager::instance()->session();
if (session && session->isSessionValid())
{
return true;
}
else
{
return false;
}
}
//--------------------------------------------------------------------------------------------------
@ -44,12 +51,22 @@ bool RicHoloLensExportToSharingServerFeature::isCommandEnabled()
//--------------------------------------------------------------------------------------------------
void RicHoloLensExportToSharingServerFeature::onActionTriggered(bool isChecked)
{
RicHoloLensSession* session = RicHoloLensSessionManager::instance()->session();
if (!session || !session->isSessionValid())
{
RiaLogging::error("No valid HoloLens session present");
return;
}
RimGridView* activeView = RiaApplication::instance()->activeGridView();
if (!activeView)
{
RiaLogging::error("No active view");
return;
}
if (!activeView) return;
VdeFileExporter exporter("dummypath");
exporter.exportViewContents(*activeView);
session->updateSessionDataFromView(*activeView);
}
//--------------------------------------------------------------------------------------------------

View File

@ -0,0 +1,360 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight 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 GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicHoloLensRestClient.h"
#include "cvfBase.h"
#include "cvfTrace.h"
#include <QNetworkRequest>
#include <QSslConfiguration>
#ifndef QT_NO_OPENSSL
// Uncomment to enable experimental SSL support
// The experimental support must be revised before shipping
#define EXPERIMENTAL_SSL_SUPPORT
#endif
//==================================================================================================
//
//
//
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RicHoloLensRestClient::RicHoloLensRestClient(QString serverUrl, QString sessionName, RicHoloLensRestResponseHandler* responseHandler)
: m_serverUrl(serverUrl),
m_sessionName(sessionName),
m_responseHandler(responseHandler)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensRestClient::clearResponseHandler()
{
m_responseHandler = nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensRestClient::createSession()
{
const QString url = m_serverUrl + "/sessions/create/" + m_sessionName;
cvf::Trace::show("createSession: POST on url: %s", url.toLatin1().constData());
QNetworkRequest request(url);
//request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded"));
#ifdef EXPERIMENTAL_SSL_SUPPORT
// NOTE !!!
// Apparently something like this is currently needed in order to get SSL/HTTPS going
// Still, can't quite figure it out since it appears to be sufficient to do this on the first request
// This will have to be investigated further, SP 20181924
QSslConfiguration sslConf = request.sslConfiguration();
// Needed this one to be able to connect to sharing server
sslConf.setProtocol(QSsl::AnyProtocol);
// !!MUST!! remove this code in production
sslConf.setPeerVerifyMode(QSslSocket::VerifyNone);
request.setSslConfiguration(sslConf);
#endif
QNetworkReply* reply = m_accessManager.post(request, QByteArray());
connect(reply, SIGNAL(finished()), SLOT(slotCreateSessionFinished()));
#ifdef EXPERIMENTAL_SSL_SUPPORT
connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), SLOT(slotSslErrors(const QList<QSslError>&)));
#endif
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensRestClient::slotCreateSessionFinished()
{
QNetworkReply* reply = dynamic_cast<QNetworkReply*>(sender());
if (!reply)
{
return;
}
if (detectAndHandleErrorReply("createSession", reply))
{
reply->deleteLater();
return;
}
reply->deleteLater();
cvf::Trace::show("createSession OK");
if (m_responseHandler)
{
m_responseHandler->handleSuccessfulCreateSession();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensRestClient::deleteSession()
{
const QString url = m_serverUrl + "/sessions/delete/" + m_sessionName;
cvf::Trace::show("deleteSession: DELETE on url: %s", url.toLatin1().constData());
QNetworkRequest request(url);
//request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded"));
QNetworkReply* reply = m_accessManager.deleteResource(request);
connect(reply, SIGNAL(finished()), SLOT(slotDeleteSessionFinished()));
#ifdef EXPERIMENTAL_SSL_SUPPORT
connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), SLOT(slotSslErrors(const QList<QSslError>&)));
#endif
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensRestClient::slotDeleteSessionFinished()
{
QNetworkReply* reply = dynamic_cast<QNetworkReply*>(sender());
if (!reply)
{
return;
}
if (detectAndHandleErrorReply("deleteSession", reply))
{
reply->deleteLater();
return;
}
reply->deleteLater();
cvf::Trace::show("deleteSession OK");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensRestClient::sendMetaData(int metaDataSequenceNumber, const QString& jsonMetaDataString)
{
const QString url = m_serverUrl + "/sessions/" + m_sessionName + "/metadata";
cvf::Trace::show("sendMetaData (metaDataSequenceNumber=%d): POST on url: %s", metaDataSequenceNumber, url.toLatin1().constData());
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));
const QByteArray jsonByteArr = jsonMetaDataString.toLatin1();
QNetworkReply* reply = m_accessManager.post(request, jsonByteArr);
reply->setProperty("metaDataSequenceNumber", QVariant(metaDataSequenceNumber));
connect(reply, SIGNAL(finished()), SLOT(slotSendMetaDataFinished()));
#ifdef EXPERIMENTAL_SSL_SUPPORT
connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), SLOT(slotSslErrors(const QList<QSslError>&)));
#endif
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensRestClient::slotSendMetaDataFinished()
{
QNetworkReply* reply = dynamic_cast<QNetworkReply*>(sender());
if (!reply)
{
return;
}
if (detectAndHandleErrorReply("sendMetaData", reply))
{
reply->deleteLater();
return;
}
int metaDataSequenceNumber = -1;
{
QVariant var = reply->property("metaDataSequenceNumber");
if (var.type() == QVariant::Int)
{
metaDataSequenceNumber = var.toInt();
}
}
reply->deleteLater();
cvf::Trace::show("sendMetaData (metaDataSequenceNumber=%d) OK", metaDataSequenceNumber);
if (m_responseHandler)
{
m_responseHandler->handleSuccessfulSendMetaData(metaDataSequenceNumber);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensRestClient::sendBinaryData(const QByteArray& binaryDataArr)
{
const QString url = m_serverUrl + "/sessions/" + m_sessionName + "/data";
cvf::Trace::show("sendBinaryData: POST on url: %s", url.toLatin1().constData());
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
QNetworkReply* reply = m_accessManager.post(request, binaryDataArr);
connect(reply, SIGNAL(finished()), SLOT(slotSendBinaryDataFinished()));
#ifdef EXPERIMENTAL_SSL_SUPPORT
connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), SLOT(slotSslErrors(const QList<QSslError>&)));
#endif
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensRestClient::slotSendBinaryDataFinished()
{
QNetworkReply* reply = dynamic_cast<QNetworkReply*>(sender());
if (!reply)
{
return;
}
if (detectAndHandleErrorReply("sendBinaryData", reply))
{
reply->deleteLater();
return;
}
reply->deleteLater();
cvf::Trace::show("sendBinaryData OK");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensRestClient::slotSslErrors(const QList<QSslError>& errors)
{
#ifdef EXPERIMENTAL_SSL_SUPPORT
cvf::Trace::show("RicHoloLensRestClient::slotSslErrors()");
for (int i = 0; i < errors.size(); i++)
{
cvf::Trace::show(" %s", errors[i].errorString().toLatin1().constData());
}
#endif
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicHoloLensRestClient::detectAndHandleErrorReply(QString operationName, QNetworkReply* reply)
{
CVF_ASSERT(reply);
const QNetworkReply::NetworkError nwErrCode = reply->error();
const int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (nwErrCode == QNetworkReply::NoError && httpStatusCode == 200)
{
// No error detected
return false;
}
QString mainErrMsg = operationName + " FAILED";
if (nwErrCode != QNetworkReply::NoError)
{
const QString nwErrCodeAsString = networkErrorCodeAsString(nwErrCode);
const QString errText = reply->errorString();
mainErrMsg += QString(" [nwErr='%1'(%2) httpStatus=%3]: %4").arg(nwErrCodeAsString).arg(nwErrCode).arg(httpStatusCode).arg(errText);
}
else
{
mainErrMsg += QString(" [httpStatus=%1]").arg(httpStatusCode);
}
cvf::Trace::show(mainErrMsg.toLatin1().constData());
reply->errorString();
const QString url = reply->url().toString();
cvf::Trace::show(" url: %s", url.toLatin1().constData());
const QByteArray serverData = reply->readAll();
cvf::Trace::show(" serverResponse: %s", serverData.constData());
if (m_responseHandler)
{
m_responseHandler->handleError(mainErrMsg, url, serverData);
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RicHoloLensRestClient::networkErrorCodeAsString(QNetworkReply::NetworkError nwErr)
{
switch (nwErr)
{
case QNetworkReply::NoError: return "NoError";
case QNetworkReply::ConnectionRefusedError: return "ConnectionRefusedError";
case QNetworkReply::RemoteHostClosedError: return "RemoteHostClosedError";
case QNetworkReply::HostNotFoundError: return "HostNotFoundError";
case QNetworkReply::TimeoutError: return "TimeoutError";
case QNetworkReply::OperationCanceledError: return "OperationCanceledError";
case QNetworkReply::SslHandshakeFailedError: return "SslHandshakeFailedError";
//case QNetworkReply::TemporaryNetworkFailureError: return "TemporaryNetworkFailureError";
case QNetworkReply::UnknownNetworkError: return "UnknownNetworkError";
case QNetworkReply::ProxyConnectionRefusedError: return "ProxyConnectionRefusedError";
case QNetworkReply::ProxyConnectionClosedError: return "ProxyConnectionClosedError";
case QNetworkReply::ProxyNotFoundError: return "ProxyNotFoundError";
case QNetworkReply::ProxyTimeoutError: return "ProxyTimeoutError";
case QNetworkReply::ProxyAuthenticationRequiredError: return "ProxyAuthenticationRequiredError";
case QNetworkReply::UnknownProxyError: return "UnknownProxyError";
case QNetworkReply::ContentAccessDenied: return "ContentAccessDenied";
case QNetworkReply::ContentOperationNotPermittedError: return "ContentOperationNotPermittedError";
case QNetworkReply::ContentNotFoundError: return "ContentNotFoundError";
case QNetworkReply::AuthenticationRequiredError: return "AuthenticationRequiredError";
case QNetworkReply::ContentReSendError: return "ContentReSendError";
case QNetworkReply::UnknownContentError: return "UnknownContentError";
case QNetworkReply::ProtocolUnknownError: return "ProtocolUnknownError";
case QNetworkReply::ProtocolInvalidOperationError: return "ProtocolInvalidOperationError";
case QNetworkReply::ProtocolFailure: return "ProtocolFailure";
};
return "UnknownErrorCode";
}

View File

@ -0,0 +1,79 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight 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 GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
//==================================================================================================
//
//
//
//==================================================================================================
class RicHoloLensRestResponseHandler
{
public:
virtual void handleSuccessfulCreateSession() = 0;
virtual void handleSuccessfulSendMetaData(int metaDataSequenceNumber) = 0;
virtual void handleError(const QString& errMsg, const QString& url, const QString& serverData) = 0;
};
//==================================================================================================
//
//
//
//==================================================================================================
class RicHoloLensRestClient : public QObject
{
Q_OBJECT
public:
RicHoloLensRestClient(QString serverUrl, QString sessionName, RicHoloLensRestResponseHandler* responseHandler);
void clearResponseHandler();
void createSession();
void deleteSession();
void sendMetaData(int metaDataSequenceNumber, const QString& jsonMetaDataString);
void sendBinaryData(const QByteArray& binaryDataArr);
private:
bool detectAndHandleErrorReply(QString operationName, QNetworkReply* reply);
static QString networkErrorCodeAsString(QNetworkReply::NetworkError nwErr);
private slots:
void slotCreateSessionFinished();
void slotDeleteSessionFinished();
void slotSendMetaDataFinished();
void slotSendBinaryDataFinished();
void slotSslErrors(const QList<QSslError>& errors);
private:
QNetworkAccessManager m_accessManager;
QString m_serverUrl;
QString m_sessionName;
RicHoloLensRestResponseHandler* m_responseHandler;
};

View File

@ -17,64 +17,99 @@
/////////////////////////////////////////////////////////////////////////////////
#include "RicHoloLensSession.h"
#include "RicHoloLensSessionManager.h"
#include "RiaLogging.h"
#include "RiaPreferences.h"
#include "cafCmdFeatureManager.h"
#include "VdeVizDataExtractor.h"
#include "VdeFileExporter.h"
#include "VdePacketDirectory.h"
#include "VdeArrayDataPacket.h"
#include "cvfAssert.h"
#include <QDir>
//==================================================================================================
//
//
//
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RicHoloLensSession::RicHoloLensSession()
: m_isSessionValid(false)
, m_isIsFileBackedSessionValid(false)
: m_isSessionValid(false),
m_lastExtractionMetaDataSequenceNumber(-1),
m_dbgEnableFileExport(false)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RicHoloLensSession* RicHoloLensSession::instance()
RicHoloLensSession::~RicHoloLensSession()
{
static RicHoloLensSession theInstance;
return &theInstance;
destroySession();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicHoloLensSession::createSession(const QString& serverUrl, const QString& sessionName, const QString& sessionPinCode)
RicHoloLensSession* RicHoloLensSession::createSession(const QString& serverUrl, const QString& sessionName)
{
if (isSessionValid())
RicHoloLensSession* newSession = new RicHoloLensSession;
newSession->m_restClient = new RicHoloLensRestClient(serverUrl, sessionName, newSession);
newSession->m_restClient->createSession();
// For now, leave this on!!!
// We probably want to export this as a preference parameter
newSession->m_dbgEnableFileExport = true;
return newSession;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RicHoloLensSession* RicHoloLensSession::createDummyFileBackedSession()
{
RicHoloLensSession* newSession = new RicHoloLensSession;
newSession->m_isSessionValid = true;
newSession->m_dbgEnableFileExport = true;
return newSession;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensSession::destroySession()
{
if (m_restClient)
{
RiaLogging::error("Terminate existing session before creating a new session");
return false;
if (m_isSessionValid)
{
m_restClient->deleteSession();
}
m_restClient->clearResponseHandler();
m_restClient->deleteLater();
m_restClient = nullptr;
}
RiaLogging::info("url : " + serverUrl + " name : " + sessionName + " pinCode : " + sessionPinCode);
m_isSessionValid = false;
m_isSessionValid = true;
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicHoloLensSession::createDummyFileBackedSession()
{
if (isSessionValid())
{
RiaLogging::error("Terminate existing session before creating a new session");
return false;
}
m_isIsFileBackedSessionValid = true;
return true;
m_lastExtractionMetaDataSequenceNumber = -1;
m_lastExtractionAllReferencedPacketIdsArr.clear();
m_packetDirectory.clear();
}
//--------------------------------------------------------------------------------------------------
@ -82,50 +117,117 @@ bool RicHoloLensSession::createDummyFileBackedSession()
//--------------------------------------------------------------------------------------------------
bool RicHoloLensSession::isSessionValid() const
{
if (m_isIsFileBackedSessionValid) return true;
return m_isSessionValid;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicHoloLensSession::isFileBackedSessionValid() const
{
return m_isIsFileBackedSessionValid;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensSession::updateSessionDataFromView(RimGridView* activeView)
void RicHoloLensSession::updateSessionDataFromView(const RimGridView& activeView)
{
RiaLogging::info("HoloLens : updateSessionDataFromView");
}
RiaLogging::info("HoloLens: Updating visualization data");
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensSession::terminateSession()
{
if (!isSessionValid()) return;
QString modelMetaJsonStr;
std::vector<int> allReferencedPacketIds;
m_packetDirectory.clear();
RiaLogging::info("Terminating HoloLens Session");
VdeVizDataExtractor extractor(activeView);
extractor.extractViewContents(&modelMetaJsonStr, &allReferencedPacketIds, &m_packetDirectory);
m_isIsFileBackedSessionValid = false;
m_isSessionValid = false;
m_lastExtractionMetaDataSequenceNumber++;
m_lastExtractionAllReferencedPacketIdsArr = allReferencedPacketIds;
if (m_restClient)
{
RiaLogging::info(QString("HoloLens: Sending updated meta data to sharing server (sequenceNumber=%1)").arg(m_lastExtractionMetaDataSequenceNumber));
m_restClient->sendMetaData(m_lastExtractionMetaDataSequenceNumber, modelMetaJsonStr);
}
// Debug export to file
if (m_dbgEnableFileExport)
{
const QString folderName = RiaApplication::instance()->preferences()->holoLensExportFolder();
if (folderName.isEmpty())
{
RiaLogging::warning("HoloLens: Debug export to file enabled, but no export folder has been set");
return;
}
const QDir outputDir(folderName);
const QString absOutputFolder = outputDir.absolutePath();
if (!outputDir.mkpath("."))
{
RiaLogging::error(QString("HoloLens: Could not create debug file export folder: %1").arg(absOutputFolder));
return;
}
RiaLogging::info(QString("HoloLens: Doing debug export of data to folder: %1").arg(absOutputFolder));
VdeFileExporter fileExporter(absOutputFolder);
if (!fileExporter.exportToFile(modelMetaJsonStr, m_packetDirectory, allReferencedPacketIds))
{
RiaLogging::error("HoloLens: Error exporting debug data to folder");
}
RiaLogging::info("HoloLens: Done exporting debug data");
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensSession::refreshToolbarState()
void RicHoloLensSession::handleSuccessfulCreateSession()
{
QStringList commandIds;
RiaLogging::info("HoloLens: Session successfully created");
m_isSessionValid = true;
commandIds << "RicHoloLensCreateSessionFeature";
commandIds << "RicHoloLensExportToSharingServerFeature";
commandIds << "RicHoloLensTerminateSessionFeature";
caf::CmdFeatureManager::instance()->refreshEnabledState(commandIds);
// Slight hack here - reaching out to the manager to update GUI
// We should really just be notifying the manager that our state has changed
RicHoloLensSessionManager::refreshToolbarState();
}
//--------------------------------------------------------------------------------------------------
/// Handle the server response we receive after sending new meta data
//--------------------------------------------------------------------------------------------------
void RicHoloLensSession::handleSuccessfulSendMetaData(int metaDataSequenceNumber)
{
RiaLogging::info(QString("HoloLens: Processing server response to meta data (sequenceNumber=%1)").arg(metaDataSequenceNumber));
if (m_lastExtractionMetaDataSequenceNumber != metaDataSequenceNumber)
{
RiaLogging::warning(QString("HoloLens: Ignoring server response, the sequenceNumber(%1) has been superseded").arg(metaDataSequenceNumber));
return;
}
if (m_lastExtractionAllReferencedPacketIdsArr.size() > 0)
{
QByteArray combinedPacketArr;
if (!m_packetDirectory.getPacketsAsCombinedBuffer(m_lastExtractionAllReferencedPacketIdsArr, &combinedPacketArr))
{
RiaLogging::warning("HoloLens: Error gathering the requested packets, no data will be sent");
return;
}
RiaLogging::info(QString("HoloLens: Sending new data to sharing server (%1 packets)").arg(m_lastExtractionAllReferencedPacketIdsArr.size()));
m_restClient->sendBinaryData(combinedPacketArr);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensSession::handleError(const QString& errMsg, const QString& url, const QString& serverData)
{
QString fullMsg = "HoloLens communication error: " + errMsg;
if (!serverData.isEmpty())
{
fullMsg += "\n serverMsg: " + serverData;
}
fullMsg += "\n url: " + url;
RiaLogging::error(fullMsg);
}

View File

@ -18,32 +18,54 @@
#pragma once
#include "RicHoloLensRestClient.h"
#include "VdePacketDirectory.h"
#include <QString>
#include <QPointer>
#include <vector>
class RimGridView;
//==================================================================================================
///
//
//
//
//==================================================================================================
class RicHoloLensSession
class RicHoloLensSession : public QObject, private RicHoloLensRestResponseHandler
{
public:
RicHoloLensSession();
~RicHoloLensSession();
static RicHoloLensSession* instance();
static RicHoloLensSession* createSession(const QString& serverUrl, const QString& sessionName);
static RicHoloLensSession* createDummyFileBackedSession();
void destroySession();
bool createSession(const QString& serverUrl, const QString& sessionName, const QString& sessionPinCode);
bool createDummyFileBackedSession();
bool isSessionValid() const;
bool isSessionValid() const;
bool isFileBackedSessionValid() const;
void updateSessionDataFromView(RimGridView* activeView);
void terminateSession();
static void refreshToolbarState();
void updateSessionDataFromView(const RimGridView& activeView);
private:
bool m_isSessionValid;
bool m_isIsFileBackedSessionValid;
RicHoloLensSession();
virtual void handleSuccessfulCreateSession() override;
virtual void handleSuccessfulSendMetaData(int metaDataSequenceNumber) override;
virtual void handleError(const QString& errMsg, const QString& url, const QString& serverData) override;
private:
bool m_isSessionValid;
QPointer<RicHoloLensRestClient> m_restClient;
int m_lastExtractionMetaDataSequenceNumber;
std::vector<int> m_lastExtractionAllReferencedPacketIdsArr;
VdePacketDirectory m_packetDirectory;
bool m_dbgEnableFileExport;
};

View File

@ -0,0 +1,127 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight 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 GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicHoloLensSessionManager.h"
#include "RicHoloLensSession.h"
#include "RiaLogging.h"
#include "cafCmdFeatureManager.h"
//==================================================================================================
//
//
//
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RicHoloLensSessionManager::RicHoloLensSessionManager()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RicHoloLensSessionManager* RicHoloLensSessionManager::instance()
{
static RicHoloLensSessionManager theInstance;
return &theInstance;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicHoloLensSessionManager::createSession(const QString& serverUrl, const QString& sessionName, const QString& /*sessionPinCode*/)
{
if (m_session)
{
RiaLogging::error("Terminate existing session before creating a new session");
return false;
}
RiaLogging::info(QString("Creating HoloLens session: '%1', server url: %2").arg(sessionName).arg(serverUrl));
m_session = RicHoloLensSession::createSession(serverUrl, sessionName);
refreshToolbarState();
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicHoloLensSessionManager::createDummyFileBackedSession()
{
if (m_session)
{
RiaLogging::error("Terminate existing session before creating a new session");
return false;
}
m_session = RicHoloLensSession::createDummyFileBackedSession();
RiaLogging::info("Created dummy file-backed HoloLens session");
refreshToolbarState();
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensSessionManager::terminateSession()
{
if (!m_session)
{
return;
}
RiaLogging::info("Terminating HoloLens session");
m_session->destroySession();
m_session->deleteLater();
m_session = nullptr;
refreshToolbarState();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RicHoloLensSession* RicHoloLensSessionManager::session()
{
return m_session;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHoloLensSessionManager::refreshToolbarState()
{
QStringList commandIds;
commandIds << "RicHoloLensCreateSessionFeature";
commandIds << "RicHoloLensExportToSharingServerFeature";
commandIds << "RicHoloLensTerminateSessionFeature";
caf::CmdFeatureManager::instance()->refreshEnabledState(commandIds);
}

View File

@ -0,0 +1,53 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight 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 GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RicHoloLensRestClient.h"
#include <QPointer>
class RicHoloLensSession;
//==================================================================================================
//
//
//
//==================================================================================================
class RicHoloLensSessionManager
{
public:
static RicHoloLensSessionManager* instance();
bool createSession(const QString& serverUrl, const QString& sessionName, const QString& sessionPinCode);
bool createDummyFileBackedSession();
void terminateSession();
RicHoloLensSession* session();
static void refreshToolbarState();
private:
RicHoloLensSessionManager();
private:
QPointer<RicHoloLensSession> m_session;
};

View File

@ -18,7 +18,7 @@
#include "RicHoloLensTerminateSessionFeature.h"
#include "RicHoloLensSession.h"
#include "RicHoloLensSessionManager.h"
#include "RiaLogging.h"
#include "RiaQIconTools.h"
@ -32,7 +32,7 @@ CAF_CMD_SOURCE_INIT(RicHoloLensTerminateSessionFeature, "RicHoloLensTerminateSes
//--------------------------------------------------------------------------------------------------
bool RicHoloLensTerminateSessionFeature::isCommandEnabled()
{
return RicHoloLensSession::instance()->isSessionValid();
return RicHoloLensSessionManager::instance()->session() ? true : false;
}
//--------------------------------------------------------------------------------------------------
@ -40,9 +40,9 @@ bool RicHoloLensTerminateSessionFeature::isCommandEnabled()
//--------------------------------------------------------------------------------------------------
void RicHoloLensTerminateSessionFeature::onActionTriggered(bool isChecked)
{
RicHoloLensSession::instance()->terminateSession();
RicHoloLensSessionManager::instance()->terminateSession();
RicHoloLensSession::refreshToolbarState();
RicHoloLensSessionManager::refreshToolbarState();
}
//--------------------------------------------------------------------------------------------------

View File

@ -18,24 +18,10 @@
#include "VdeFileExporter.h"
#include "VdeArrayDataPacket.h"
#include "VdePacketDirectory.h"
#include "RicHoloLensExportImpl.h"
#include "RifJsonEncodeDecode.h"
#include "RiaLogging.h"
#include "cvfPart.h"
#include "cvfScene.h"
#include "cvfDrawableGeo.h"
#include "cvfPrimitiveSet.h"
#include "cvfTransform.h"
#include "cvfRenderStateTextureBindings.h"
#include "cvfTexture.h"
#include "cvfEffect.h"
#include "cvfTrace.h"
#include <QString>
#include <QDir>
#include <QFile>
@ -58,90 +44,35 @@ VdeFileExporter::VdeFileExporter(QString absOutputFolder)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool VdeFileExporter::exportViewContents(const RimGridView& view)
bool VdeFileExporter::exportToFile(const QString& modelMetaJsonStr, const VdePacketDirectory& packetDirectory, const std::vector<int>& packetIdsToExport)
{
std::vector<VdeExportPart> exportPartsArr = RicHoloLensExportImpl::partsForExport(view);
std::vector<VdeMesh> meshArr;
for (const auto& exportPart : exportPartsArr)
{
VdeMesh mesh;
if (extractMeshFromExportPart(exportPart, &mesh))
{
meshArr.push_back(mesh);
}
}
std::vector<VdeMeshArrayIds> meshArrayIdsArr;
const size_t meshCount = meshArr.size();
cvf::Trace::show("Exporting %d meshes", meshCount);
size_t totNumPrimitives = 0;
int nextArrayId = 0;
for (size_t i = 0; i < meshCount; i++)
{
const VdeMesh& mesh = meshArr[i];
const size_t primCount = mesh.connArr.size()/mesh.verticesPerPrimitive;
totNumPrimitives += primCount;
cvf::Trace::show(" %2d: primCount=%d meshSourceObjName='%s'", i, primCount, mesh.meshSourceObjName.toLatin1().constData());
VdeMeshArrayIds meshArrayIds;
{
cvf::Trace::show(" exporting vertices");
meshArrayIds.vertexArrId = nextArrayId++;
const float* floatArr = reinterpret_cast<const float*>(mesh.vertexArr->ptr());
VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromFloat32Arr(meshArrayIds.vertexArrId, floatArr, 3*mesh.vertexArr->size());
writeDataPacketToFile(dataPacket.arrayId(), dataPacket);
// Debug testing of decoding
//debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr));
}
{
cvf::Trace::show(" exporting connectivities");
meshArrayIds.connArrId = nextArrayId++;
const unsigned int* uintArr = mesh.connArr.data();
VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromUint32Arr(meshArrayIds.connArrId, uintArr, mesh.connArr.size());
writeDataPacketToFile(dataPacket.arrayId(), dataPacket);
// Debug testing of decoding
//debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr));
}
if (mesh.texCoordArr.notNull() && mesh.texImage.notNull())
{
{
cvf::Trace::show(" exporting texture coords");
meshArrayIds.texCoordsArrId = nextArrayId++;
const float* floatArr = reinterpret_cast<const float*>(mesh.texCoordArr->ptr());
VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromFloat32Arr(meshArrayIds.texCoordsArrId, floatArr, 2*mesh.texCoordArr->size());
writeDataPacketToFile(dataPacket.arrayId(), dataPacket);
// Debug testing of decoding
//debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr));
}
{
cvf::Trace::show(" exporting texture image");
meshArrayIds.texImageArrId = nextArrayId++;
cvf::ref<cvf::UByteArray> byteArr = mesh.texImage->toRgb();
VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromUint8ImageRGBArr(meshArrayIds.texImageArrId, mesh.texImage->width(), mesh.texImage->height(), byteArr->ptr(), byteArr->size());
writeDataPacketToFile(dataPacket.arrayId(), dataPacket);
// Debug testing of decoding
//debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr));
}
}
meshArrayIdsArr.push_back(meshArrayIds);
}
cvf::Trace::show("Exporting to folder: %s", m_absOutputFolder.toLatin1().constData());
QString jsonFileName = m_absOutputFolder + "/modelMeta.json";
if (!writeModelMetaJsonFile(meshArr, meshArrayIdsArr, jsonFileName))
if (!writeModelMetaJsonFile(modelMetaJsonStr, jsonFileName))
{
cvf::Trace::show("Error writing: %s", jsonFileName.toLatin1().constData());
return false;
}
cvf::Trace::show("Total number of primitives exported: %d", totNumPrimitives);
for (const int packetArrayId : packetIdsToExport)
{
const VdeArrayDataPacket* dataPacket = packetDirectory.lookupPacket(packetArrayId);
if (!dataPacket)
{
cvf::Trace::show("Error during export, no data for arrayId %d", packetArrayId);
return false;
}
CVF_ASSERT(packetArrayId == dataPacket->arrayId());
if (!writeDataPacketToFile(dataPacket->arrayId(), *dataPacket))
{
cvf::Trace::show("Error writing packet data to file, arrayId %d", packetArrayId);
return false;
}
}
cvf::Trace::show("Data exported to folder: %s", m_absOutputFolder.toLatin1().constData());
return true;
}
@ -149,107 +80,23 @@ bool VdeFileExporter::exportViewContents(const RimGridView& view)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool VdeFileExporter::extractMeshFromExportPart(const VdeExportPart& exportPart, VdeMesh* mesh)
bool VdeFileExporter::exportViewContents(const RimGridView& view)
{
const cvf::Part* cvfPart = exportPart.part();
const cvf::DrawableGeo* geo = dynamic_cast<const cvf::DrawableGeo*>(cvfPart ? cvfPart->drawable() : nullptr);
if (!geo)
QString modelMetaJsonStr;
std::vector<int> allReferencedArrayIds;
VdePacketDirectory packetDirectory;
VdeVizDataExtractor extractor(view);
extractor.extractViewContents(&modelMetaJsonStr, &allReferencedArrayIds, &packetDirectory);
if (!exportToFile(modelMetaJsonStr, packetDirectory, allReferencedArrayIds))
{
return false;
}
if (geo->primitiveSetCount() != 1)
{
RiaLogging::debug("Only geometries with exactly one primitive set is supported");
return false;
}
const cvf::Vec3fArray* vertexArr = geo->vertexArray();
const cvf::PrimitiveSet* primSet = geo->primitiveSet(0);
if (!vertexArr || !primSet || primSet->faceCount() == 0)
{
return false;
}
// Support 2 or 3 vertices per primitive
const cvf::PrimitiveType primType = primSet->primitiveType();
if (primType != cvf::PT_TRIANGLES && primType != cvf::PT_LINES)
{
RiaLogging::debug(QString("Currently only triangle and line primitive sets are supported (saw primitive type: %1)").arg(primType));
return false;
}
const int vertsPerPrimitive = (primType == cvf::PT_TRIANGLES) ? 3 : 2;
mesh->verticesPerPrimitive = vertsPerPrimitive;
// Possibly transform the vertices
if (cvfPart->transform())
{
const size_t vertexCount = vertexArr->size();
cvf::ref<cvf::Vec3fArray> transVertexArr = new cvf::Vec3fArray(vertexArr->size());
cvf::Mat4f m = cvf::Mat4f(cvfPart->transform()->worldTransform());
for (size_t i = 0; i < vertexCount; i++)
{
transVertexArr->set(i, vertexArr->get(i).getTransformedPoint(m));
}
mesh->vertexArr = transVertexArr.p();
}
else
{
mesh->vertexArr = vertexArr;
}
// Fetch connectivities
// Using getFaceIndices() allows us to access strips and fans in the same way as triangles
// Note that HoloLens visualization wants triangles in clockwise order so we try and fix the winding
// This point might be moot if the HoloLens visualization always has to use two-sideded lighting to get good results
cvf::UIntArray faceConn;
const size_t faceCount = primSet->faceCount();
for (size_t iface = 0; iface < faceCount; iface++)
{
primSet->getFaceIndices(iface, &faceConn);
if (vertsPerPrimitive == 3 && exportPart.winding() == VdeExportPart::COUNTERCLOCKWISE)
{
// Reverse the winding
const size_t numConn = faceConn.size();
for (size_t i = 0; i < numConn; i++)
{
mesh->connArr.push_back(faceConn[numConn - i - 1]);
}
}
else
{
mesh->connArr.insert(mesh->connArr.end(), faceConn.begin(), faceConn.end());
}
}
if (exportPart.textureImage() && geo->textureCoordArray())
{
mesh->texCoordArr = geo->textureCoordArray();
mesh->texImage = exportPart.textureImage();
}
QString srcObjType = "unknown";
if (exportPart.sourceObjectType() == VdeExportPart::OBJ_TYPE_GRID) srcObjType = "grid";
else if (exportPart.sourceObjectType() == VdeExportPart::OBJ_TYPE_PIPE) srcObjType = "pipe";
mesh->meshSourceObjTypeStr = srcObjType;
mesh->meshSourceObjName = exportPart.sourceObjectName();
mesh->color = exportPart.color();
mesh->opacity = exportPart.opacity();
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -274,50 +121,9 @@ bool VdeFileExporter::writeDataPacketToFile(int arrayId, const VdeArrayDataPacke
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool VdeFileExporter::writeModelMetaJsonFile(const std::vector<VdeMesh>& meshArr, const std::vector<VdeMeshArrayIds>& meshContentIdsArr, QString fileName)
bool VdeFileExporter::writeModelMetaJsonFile(const QString& modelMetaJsonStr, QString fileName)
{
QVariantList jsonMeshMetaList;
for (size_t i = 0; i < meshArr.size(); i++)
{
const VdeMesh& mesh = meshArr[i];
const VdeMeshArrayIds& meshIds = meshContentIdsArr[i];
QMap<QString, QVariant> jsonMeshMeta;
jsonMeshMeta["meshSourceObjType"] = mesh.meshSourceObjTypeStr;
jsonMeshMeta["meshSourceObjName"] = mesh.meshSourceObjName;
jsonMeshMeta["verticesPerPrimitive"] = mesh.verticesPerPrimitive;
jsonMeshMeta["vertexArrId"] = meshIds.vertexArrId;
jsonMeshMeta["connArrId"] = meshIds.connArrId;
if (meshIds.texCoordsArrId >= 0 && meshIds.texImageArrId >= 0)
{
jsonMeshMeta["texCoordsArrId"] = meshIds.texCoordsArrId;
jsonMeshMeta["texImageArrId"] = meshIds.texImageArrId;
}
else
{
QMap<QString, QVariant> jsonColor;
jsonColor["r"] = mesh.color.r();
jsonColor["g"] = mesh.color.g();
jsonColor["b"] = mesh.color.b();
jsonMeshMeta["color"] = jsonColor;
}
jsonMeshMeta["opacity"] = mesh.opacity;
jsonMeshMetaList.push_back(jsonMeshMeta);
}
QMap<QString, QVariant> jsonModelMeta;
jsonModelMeta["modelName"] = "ResInsightExport";
jsonModelMeta["meshArr"] = jsonMeshMetaList;
ResInsightInternalJson::Json jsonCodec;
const bool prettifyJson = true;
QByteArray jsonStr = jsonCodec.encode(jsonModelMeta, prettifyJson).toLatin1();
const QByteArray jsonByteArr = modelMetaJsonStr.toLatin1();
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
@ -325,7 +131,7 @@ bool VdeFileExporter::writeModelMetaJsonFile(const std::vector<VdeMesh>& meshArr
return false;
}
if (file.write(jsonStr) == -1)
if (file.write(jsonByteArr) == -1)
{
return false;
}
@ -333,20 +139,3 @@ bool VdeFileExporter::writeModelMetaJsonFile(const std::vector<VdeMesh>& meshArr
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void VdeFileExporter::debugComparePackets(const VdeArrayDataPacket& packetA, const VdeArrayDataPacket& packetB)
{
CVF_ASSERT(packetA.elementCount() == packetB.elementCount());
CVF_ASSERT(packetA.elementSize() == packetB.elementSize());
CVF_ASSERT(packetA.elementType() == packetB.elementType());
const char* arrA = packetA.arrayData();
const char* arrB = packetB.arrayData();
for (size_t i = 0; i < packetA.elementCount(); i++)
{
CVF_ASSERT(arrA[i] == arrB[i]);
}
}

View File

@ -18,72 +18,15 @@
#pragma once
#include "cvfBase.h"
#include "cvfCollection.h"
#include "cvfArray.h"
#include "cvfTextureImage.h"
#include "VdeVizDataExtractor.h"
#include <QString>
class VdeArrayDataPacket;
class VdeExportPart;
class VdePacketDirectory;
class RimGridView;
namespace cvf
{
class Part;
}
//==================================================================================================
//
//
//
//==================================================================================================
struct VdeMesh
{
QString meshSourceObjTypeStr;
QString meshSourceObjName;
cvf::Color3f color;
float opacity;
int verticesPerPrimitive;
cvf::cref<cvf::Vec3fArray> vertexArr;
cvf::cref<cvf::Vec2fArray> texCoordArr;
std::vector<cvf::uint> connArr;
cvf::cref<cvf::TextureImage> texImage;
VdeMesh()
: color(1,1,1),
opacity(1),
verticesPerPrimitive(-1)
{}
};
//==================================================================================================
//
//
//
//==================================================================================================
struct VdeMeshArrayIds
{
int vertexArrId;
int connArrId;
int texImageArrId;
int texCoordsArrId;
VdeMeshArrayIds()
: vertexArrId(-1),
connArrId(-1),
texImageArrId(-1),
texCoordsArrId(-1)
{}
};
//==================================================================================================
@ -96,13 +39,11 @@ class VdeFileExporter
public:
VdeFileExporter(QString absOutputFolder);
bool exportToFile(const QString& modelMetaJsonStr, const VdePacketDirectory& packetDirectory, const std::vector<int>& packetIdsToExport);
bool exportViewContents(const RimGridView& view);
private:
static bool extractMeshFromExportPart(const VdeExportPart& exportPart, VdeMesh* mesh);
static bool writeModelMetaJsonFile(const std::vector<VdeMesh>& meshArr, const std::vector<VdeMeshArrayIds>& meshContentIdsArr, QString fileName);
static void debugComparePackets(const VdeArrayDataPacket& packetA, const VdeArrayDataPacket& packetB);
static bool writeModelMetaJsonFile(const QString& modelMetaJsonStr, QString fileName);
bool writeDataPacketToFile(int arrayId, const VdeArrayDataPacket& packet) const;
private:

View File

@ -0,0 +1,87 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight 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 GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "VdePacketDirectory.h"
//==================================================================================================
//
//
//
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VdePacketDirectory::VdePacketDirectory()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void VdePacketDirectory::addPacket(const VdeArrayDataPacket& packet)
{
const int id = packet.arrayId();
m_idToPacketMap[id] = std::unique_ptr<VdeArrayDataPacket>(new VdeArrayDataPacket(packet));
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const VdeArrayDataPacket* VdePacketDirectory::lookupPacket(int arrayId) const
{
IdToPacketMap_T::const_iterator it = m_idToPacketMap.find(arrayId);
if (it == m_idToPacketMap.end())
{
return nullptr;
}
return it->second.get();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void VdePacketDirectory::clear()
{
m_idToPacketMap.clear();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool VdePacketDirectory::getPacketsAsCombinedBuffer(const std::vector<int>& packetIdsToGet, QByteArray* combinedPacketArr) const
{
for (const int arrayId : packetIdsToGet)
{
IdToPacketMap_T::const_iterator it = m_idToPacketMap.find(arrayId);
if (it == m_idToPacketMap.end())
{
return false;
}
const VdeArrayDataPacket& packet = *it->second;
*combinedPacketArr += QByteArray::fromRawData(packet.fullPacketRawPtr(), static_cast<int>(packet.fullPacketSize()));
}
return true;
}

View File

@ -0,0 +1,50 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight 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 GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "VdeArrayDataPacket.h"
#include <QByteArray>
#include <map>
#include <memory>
//==================================================================================================
//
//
//
//==================================================================================================
class VdePacketDirectory
{
public:
VdePacketDirectory();
void addPacket(const VdeArrayDataPacket& packet);
const VdeArrayDataPacket* lookupPacket(int arrayId) const;
void clear();
bool getPacketsAsCombinedBuffer(const std::vector<int>& packetIdsToGet, QByteArray* combinedPacketArr) const;
private:
typedef std::map<int, std::unique_ptr<VdeArrayDataPacket>> IdToPacketMap_T;
IdToPacketMap_T m_idToPacketMap;
};

View File

@ -0,0 +1,331 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight 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 GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "VdeVizDataExtractor.h"
#include "VdeArrayDataPacket.h"
#include "VdePacketDirectory.h"
#include "RicHoloLensExportImpl.h"
#include "RifJsonEncodeDecode.h"
#include "RiaLogging.h"
#include "cvfDrawableGeo.h"
#include "cvfPrimitiveSet.h"
#include "cvfTransform.h"
#include "cvfTrace.h"
//==================================================================================================
//
//
//
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VdeVizDataExtractor::VdeVizDataExtractor(const RimGridView& view)
: m_view(view)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void VdeVizDataExtractor::extractViewContents(QString* modelMetaJsonStr, std::vector<int>* allReferencedArrayIds, VdePacketDirectory* packetDirectory)
{
// First extract the parts (cvfPart + info) to be exported from from the ResInsight view
const std::vector<VdeExportPart> exportPartsArr = RicHoloLensExportImpl::partsForExport(m_view);
// Convert this to an array of export ready meshes
const std::vector<VdeMesh> meshArr = buildMeshArray(exportPartsArr);
const size_t meshCount = meshArr.size();
cvf::Trace::show("Extracting %d meshes", meshCount);
std::vector<VdeMeshArrayIds> meshArrayIdsArr;
size_t totNumPrimitives = 0;
int nextArrayId = 0;
for (size_t i = 0; i < meshCount; i++)
{
const VdeMesh& mesh = meshArr[i];
const size_t primCount = mesh.connArr.size()/mesh.verticesPerPrimitive;
totNumPrimitives += primCount;
cvf::Trace::show(" %2d: primCount=%d meshSourceObjName='%s'", i, primCount, mesh.meshSourceObjName.toLatin1().constData());
VdeMeshArrayIds meshArrayIds;
{
cvf::Trace::show(" exporting vertices");
meshArrayIds.vertexArrId = nextArrayId++;
const float* floatArr = reinterpret_cast<const float*>(mesh.vertexArr->ptr());
VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromFloat32Arr(meshArrayIds.vertexArrId, floatArr, 3*mesh.vertexArr->size());
packetDirectory->addPacket(dataPacket);
// Debug testing of decoding
debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr));
}
{
cvf::Trace::show(" exporting connectivities");
meshArrayIds.connArrId = nextArrayId++;
const unsigned int* uintArr = mesh.connArr.data();
VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromUint32Arr(meshArrayIds.connArrId, uintArr, mesh.connArr.size());
packetDirectory->addPacket(dataPacket);
// Debug testing of decoding
debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr));
}
if (mesh.texCoordArr.notNull() && mesh.texImage.notNull())
{
{
cvf::Trace::show(" exporting texture coords");
meshArrayIds.texCoordsArrId = nextArrayId++;
const float* floatArr = reinterpret_cast<const float*>(mesh.texCoordArr->ptr());
VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromFloat32Arr(meshArrayIds.texCoordsArrId, floatArr, 2*mesh.texCoordArr->size());
packetDirectory->addPacket(dataPacket);
// Debug testing of decoding
debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr));
}
{
cvf::Trace::show(" exporting texture image");
meshArrayIds.texImageArrId = nextArrayId++;
cvf::ref<cvf::UByteArray> byteArr = mesh.texImage->toRgb();
VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromUint8ImageRGBArr(meshArrayIds.texImageArrId, mesh.texImage->width(), mesh.texImage->height(), byteArr->ptr(), byteArr->size());
packetDirectory->addPacket(dataPacket);
// Debug testing of decoding
debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr));
}
}
meshArrayIdsArr.push_back(meshArrayIds);
}
cvf::Trace::show("Total number of primitives extracted: %d", totNumPrimitives);
*modelMetaJsonStr = createModelMetaJsonString(meshArr, meshArrayIdsArr);
// Find all unique packet array IDs referenced
std::set<int> referencedIdsSet;
for (const VdeMeshArrayIds& meshArrayIds : meshArrayIdsArr)
{
if (meshArrayIds.vertexArrId != -1) referencedIdsSet.insert(meshArrayIds.vertexArrId);
if (meshArrayIds.connArrId != -1) referencedIdsSet.insert(meshArrayIds.connArrId);
if (meshArrayIds.texImageArrId != -1) referencedIdsSet.insert(meshArrayIds.texImageArrId);
if (meshArrayIds.texCoordsArrId != -1) referencedIdsSet.insert(meshArrayIds.texCoordsArrId);
}
allReferencedArrayIds->assign(referencedIdsSet.begin(), referencedIdsSet.end());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<VdeMesh> VdeVizDataExtractor::buildMeshArray(const std::vector<VdeExportPart>& exportPartsArr)
{
std::vector<VdeMesh> meshArr;
for (const VdeExportPart& exportPart : exportPartsArr)
{
VdeMesh mesh;
if (extractMeshFromExportPart(exportPart, &mesh))
{
meshArr.push_back(mesh);
}
}
return meshArr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool VdeVizDataExtractor::extractMeshFromExportPart(const VdeExportPart& exportPart, VdeMesh* mesh)
{
const cvf::Part* cvfPart = exportPart.part();
const cvf::DrawableGeo* geo = dynamic_cast<const cvf::DrawableGeo*>(cvfPart ? cvfPart->drawable() : nullptr);
if (!geo)
{
return false;
}
if (geo->primitiveSetCount() != 1)
{
RiaLogging::debug("Only geometries with exactly one primitive set is supported");
return false;
}
const cvf::Vec3fArray* vertexArr = geo->vertexArray();
const cvf::PrimitiveSet* primSet = geo->primitiveSet(0);
if (!vertexArr || !primSet || primSet->faceCount() == 0)
{
return false;
}
// Support 2 or 3 vertices per primitive
const cvf::PrimitiveType primType = primSet->primitiveType();
if (primType != cvf::PT_TRIANGLES && primType != cvf::PT_LINES)
{
RiaLogging::debug(QString("Currently only triangle and line primitive sets are supported (saw primitive type: %1)").arg(primType));
return false;
}
const int vertsPerPrimitive = (primType == cvf::PT_TRIANGLES) ? 3 : 2;
mesh->verticesPerPrimitive = vertsPerPrimitive;
// Possibly transform the vertices
if (cvfPart->transform())
{
const size_t vertexCount = vertexArr->size();
cvf::ref<cvf::Vec3fArray> transVertexArr = new cvf::Vec3fArray(vertexArr->size());
cvf::Mat4f m = cvf::Mat4f(cvfPart->transform()->worldTransform());
for (size_t i = 0; i < vertexCount; i++)
{
transVertexArr->set(i, vertexArr->get(i).getTransformedPoint(m));
}
mesh->vertexArr = transVertexArr.p();
}
else
{
mesh->vertexArr = vertexArr;
}
// Fetch connectivities
// Using getFaceIndices() allows us to access strips and fans in the same way as triangles
// Note that HoloLens visualization wants triangles in clockwise order so we try and fix the winding
// This point might be moot if the HoloLens visualization always has to use two-sideded lighting to get good results
cvf::UIntArray faceConn;
const size_t faceCount = primSet->faceCount();
for (size_t iface = 0; iface < faceCount; iface++)
{
primSet->getFaceIndices(iface, &faceConn);
if (vertsPerPrimitive == 3 && exportPart.winding() == VdeExportPart::COUNTERCLOCKWISE)
{
// Reverse the winding
const size_t numConn = faceConn.size();
for (size_t i = 0; i < numConn; i++)
{
mesh->connArr.push_back(faceConn[numConn - i - 1]);
}
}
else
{
mesh->connArr.insert(mesh->connArr.end(), faceConn.begin(), faceConn.end());
}
}
if (exportPart.textureImage() && geo->textureCoordArray())
{
mesh->texCoordArr = geo->textureCoordArray();
mesh->texImage = exportPart.textureImage();
}
QString srcObjType = "unknown";
if (exportPart.sourceObjectType() == VdeExportPart::OBJ_TYPE_GRID) srcObjType = "grid";
else if (exportPart.sourceObjectType() == VdeExportPart::OBJ_TYPE_PIPE) srcObjType = "pipe";
mesh->meshSourceObjTypeStr = srcObjType;
mesh->meshSourceObjName = exportPart.sourceObjectName();
mesh->color = exportPart.color();
mesh->opacity = exportPart.opacity();
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString VdeVizDataExtractor::createModelMetaJsonString(const std::vector<VdeMesh>& meshArr, const std::vector<VdeMeshArrayIds>& meshContentIdsArr)
{
QVariantList jsonMeshMetaList;
for (size_t i = 0; i < meshArr.size(); i++)
{
const VdeMesh& mesh = meshArr[i];
const VdeMeshArrayIds& meshIds = meshContentIdsArr[i];
QMap<QString, QVariant> jsonMeshMeta;
jsonMeshMeta["meshSourceObjType"] = mesh.meshSourceObjTypeStr;
jsonMeshMeta["meshSourceObjName"] = mesh.meshSourceObjName;
jsonMeshMeta["verticesPerPrimitive"] = mesh.verticesPerPrimitive;
jsonMeshMeta["vertexArrId"] = meshIds.vertexArrId;
jsonMeshMeta["connArrId"] = meshIds.connArrId;
if (meshIds.texCoordsArrId >= 0 && meshIds.texImageArrId >= 0)
{
jsonMeshMeta["texCoordsArrId"] = meshIds.texCoordsArrId;
jsonMeshMeta["texImageArrId"] = meshIds.texImageArrId;
}
else
{
QMap<QString, QVariant> jsonColor;
jsonColor["r"] = mesh.color.r();
jsonColor["g"] = mesh.color.g();
jsonColor["b"] = mesh.color.b();
jsonMeshMeta["color"] = jsonColor;
}
jsonMeshMeta["opacity"] = mesh.opacity;
jsonMeshMetaList.push_back(jsonMeshMeta);
}
QMap<QString, QVariant> jsonModelMeta;
jsonModelMeta["modelName"] = "ResInsightExport";
jsonModelMeta["meshArr"] = jsonMeshMetaList;
ResInsightInternalJson::Json jsonCodec;
const bool prettifyJson = true;
QString jsonStr = jsonCodec.encode(jsonModelMeta, prettifyJson);
return jsonStr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void VdeVizDataExtractor::debugComparePackets(const VdeArrayDataPacket& packetA, const VdeArrayDataPacket& packetB)
{
CVF_ASSERT(packetA.elementCount() == packetB.elementCount());
CVF_ASSERT(packetA.elementSize() == packetB.elementSize());
CVF_ASSERT(packetA.elementType() == packetB.elementType());
const char* arrA = packetA.arrayData();
const char* arrB = packetB.arrayData();
for (size_t i = 0; i < packetA.elementCount(); i++)
{
CVF_ASSERT(arrA[i] == arrB[i]);
}
}

View File

@ -0,0 +1,105 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight 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 GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfBase.h"
#include "cvfColor3.h"
#include "cvfArray.h"
#include "cvfTextureImage.h"
#include <QString>
class VdeArrayDataPacket;
class VdePacketDirectory;
class VdeExportPart;
class RimGridView;
//==================================================================================================
//
//
//
//==================================================================================================
struct VdeMesh
{
QString meshSourceObjTypeStr;
QString meshSourceObjName;
cvf::Color3f color;
float opacity;
int verticesPerPrimitive;
cvf::cref<cvf::Vec3fArray> vertexArr;
cvf::cref<cvf::Vec2fArray> texCoordArr;
std::vector<cvf::uint> connArr;
cvf::cref<cvf::TextureImage> texImage;
VdeMesh()
: color(1,1,1),
opacity(1),
verticesPerPrimitive(-1)
{}
};
//==================================================================================================
//
//
//
//==================================================================================================
struct VdeMeshArrayIds
{
int vertexArrId;
int connArrId;
int texImageArrId;
int texCoordsArrId;
VdeMeshArrayIds()
: vertexArrId(-1),
connArrId(-1),
texImageArrId(-1),
texCoordsArrId(-1)
{}
};
//==================================================================================================
//
//
//
//==================================================================================================
class VdeVizDataExtractor
{
public:
VdeVizDataExtractor(const RimGridView& view);
void extractViewContents(QString* modelMetaJsonStr, std::vector<int>* allReferencedArrayIds, VdePacketDirectory* packetDirectory);
private:
static std::vector<VdeMesh> buildMeshArray(const std::vector<VdeExportPart>& exportPartsArr);
static bool extractMeshFromExportPart(const VdeExportPart& exportPart, VdeMesh* mesh);
static QString createModelMetaJsonString(const std::vector<VdeMesh>& meshArr, const std::vector<VdeMeshArrayIds>& meshContentIdsArr);
static void debugComparePackets(const VdeArrayDataPacket& packetA, const VdeArrayDataPacket& packetB);
private:
const RimGridView& m_view;
};