diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index f10595a388..28c6de9612 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -699,7 +699,7 @@ bool RiaApplication::openInputEclipseCaseFromFileNames(const QStringList& fileNa //-------------------------------------------------------------------------------------------------- void RiaApplication::createMockModel() { - openEclipseCase("Result Mock Debug Model Simple", "Result Mock Debug Model Simple"); + openEclipseCase(RimDefines::mockModelBasic(), RimDefines::mockModelBasic()); } //-------------------------------------------------------------------------------------------------- @@ -707,7 +707,7 @@ void RiaApplication::createMockModel() //-------------------------------------------------------------------------------------------------- void RiaApplication::createResultsMockModel() { - openEclipseCase("Result Mock Debug Model With Results", "Result Mock Debug Model With Results"); + openEclipseCase(RimDefines::mockModelBasicWithResults(), RimDefines::mockModelBasicWithResults()); } @@ -716,7 +716,16 @@ void RiaApplication::createResultsMockModel() //-------------------------------------------------------------------------------------------------- void RiaApplication::createLargeResultsMockModel() { - openEclipseCase("Result Mock Debug Model Large With Results", "Result Mock Debug Model Large With Results"); + openEclipseCase(RimDefines::mockModelLargeWithResults(), RimDefines::mockModelLargeWithResults()); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaApplication::createMockModelCustomized() +{ + openEclipseCase(RimDefines::mockModelCustomized(), RimDefines::mockModelCustomized()); } //-------------------------------------------------------------------------------------------------- @@ -724,7 +733,7 @@ void RiaApplication::createLargeResultsMockModel() //-------------------------------------------------------------------------------------------------- void RiaApplication::createInputMockModel() { - openInputEclipseCaseFromFileNames(QStringList("Input Mock Debug Model Simple")); + openInputEclipseCaseFromFileNames(QStringList(RimDefines::mockModelBasicInputCase())); } //-------------------------------------------------------------------------------------------------- @@ -834,7 +843,12 @@ bool RiaApplication::parseArguments() bool parseOk = progOpt.parse(cvfqt::Utils::toStringVector(arguments)); - if (!parseOk || progOpt.hasOption("help") || progOpt.hasOption("?")) + // If positional parameter functionality is to be supported, the test for existence of positionalParameters must be removed + // This is based on a pull request by @andlaus https://github.com/OPM/ResInsight/pull/162 + if (!parseOk || + progOpt.hasOption("help") || + progOpt.hasOption("?") || + progOpt.positionalParameters().size() > 0) { #if defined(_MSC_VER) && defined(_WIN32) showFormattedTextInMessageBox(m_helpText); diff --git a/ApplicationCode/Application/RiaApplication.h b/ApplicationCode/Application/RiaApplication.h index 5688087195..f026d613b6 100644 --- a/ApplicationCode/Application/RiaApplication.h +++ b/ApplicationCode/Application/RiaApplication.h @@ -81,6 +81,7 @@ class RiaApplication : public QApplication void createMockModel(); void createResultsMockModel(); void createLargeResultsMockModel(); + void createMockModelCustomized(); void createInputMockModel(); QString defaultFileDialogDirectory(const QString& dialogName); diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index d5fea80758..d4e7e4113f 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -43,7 +43,6 @@ set( APPLICATION_FILES set( USER_INTERFACE_FILES UserInterface/RiuCursors.cpp UserInterface/RiuMainWindow.cpp - UserInterface/RiuPreferencesDialog.cpp UserInterface/RiuResultInfoPanel.cpp UserInterface/RiuViewer.cpp UserInterface/RiuSimpleHistogramWidget.cpp @@ -59,6 +58,7 @@ set( SOCKET_INTERFACE_FILES SocketInterface/RiaPropertyDataCommands.cpp SocketInterface/RiaWellDataCommands.cpp SocketInterface/RiaSocketTools.cpp + SocketInterface/RiaSocketDataTransfer.cpp ) @@ -98,7 +98,6 @@ set ( QT_MOC_HEADERS ProjectDataModel/RimMimeData.h UserInterface/RiuMainWindow.h - UserInterface/RiuPreferencesDialog.h UserInterface/RiuResultInfoPanel.h UserInterface/RiuViewer.h UserInterface/RiuProcessMonitor.h @@ -155,6 +154,8 @@ list( REMOVE_ITEM RAW_SOURCES Application/RiaImageCompareReporter.cpp Application/RiaRegressionTest.cpp + SocketInterface/RiaSocketDataTransfer.cpp + FileInterface/RifEclipseInputFileTools.cpp FileInterface/RifEclipseOutputFileTools.cpp FileInterface/RifEclipseRestartFilesetAccess.cpp diff --git a/ApplicationCode/FileInterface/RifEclipseInputFileTools.cpp b/ApplicationCode/FileInterface/RifEclipseInputFileTools.cpp index 34009e4340..5feeb2908c 100644 --- a/ApplicationCode/FileInterface/RifEclipseInputFileTools.cpp +++ b/ApplicationCode/FileInterface/RifEclipseInputFileTools.cpp @@ -17,15 +17,17 @@ ///////////////////////////////////////////////////////////////////////////////// #include "RifEclipseInputFileTools.h" + #include "RifReaderEclipseOutput.h" #include "RigCaseCellResultsData.h" - #include "RigCaseData.h" + #include "cafProgressInfo.h" -#include #include +#include #include +#include #include #include @@ -34,10 +36,8 @@ #include #include "ecl_grid.h" -#include "well_state.h" #include "util.h" -#include - +#include "well_state.h" QString includeKeyword("INCLUDE"); @@ -46,6 +46,73 @@ QString editKeyword("EDIT"); QString gridKeyword("GRID"); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t findOrCreateResult(const QString& newResultName, RigCaseData* reservoir) +{ + size_t resultIndex = reservoir->results(RifReaderInterface::MATRIX_RESULTS)->findScalarResultIndex(newResultName); + if (resultIndex == cvf::UNDEFINED_SIZE_T) + { + resultIndex = reservoir->results(RifReaderInterface::MATRIX_RESULTS)->addEmptyScalarResult(RimDefines::INPUT_PROPERTY, newResultName, false); + } + + return resultIndex; +} + + +//-------------------------------------------------------------------------------------------------- +/// Read all double values from input file. To reduce memory footprint, the alternative method +/// readDoubleValuesForActiveCells() can be used, and will skip all cell values for inactive cells +//-------------------------------------------------------------------------------------------------- +bool readDoubleValues(RigCaseData* reservoir, size_t resultIndex, ecl_kw_type* eclKeyWordData) +{ + if (resultIndex == cvf::UNDEFINED_SIZE_T) return false; + + std::vector< std::vector >& newPropertyData = reservoir->results(RifReaderInterface::MATRIX_RESULTS)->cellScalarResults(resultIndex); + newPropertyData.push_back(std::vector()); + newPropertyData[0].resize(ecl_kw_get_size(eclKeyWordData), HUGE_VAL); + ecl_kw_get_data_as_double(eclKeyWordData, newPropertyData[0].data()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool readDoubleValuesForActiveCells(RigCaseData* reservoir, size_t resultIndex, ecl_kw_type* eclKeyWordData) +{ + if (resultIndex == cvf::UNDEFINED_SIZE_T) return false; + + std::vector< std::vector >& newPropertyData = reservoir->results(RifReaderInterface::MATRIX_RESULTS)->cellScalarResults(resultIndex); + newPropertyData.push_back(std::vector()); + + RigActiveCellInfo* activeCellInfo = reservoir->activeCellInfo(RifReaderInterface::MATRIX_RESULTS); + if (activeCellInfo->globalCellCount() > 0 && activeCellInfo->globalCellCount() != activeCellInfo->globalActiveCellCount()) + { + std::vector valuesAllCells; + valuesAllCells.resize(ecl_kw_get_size(eclKeyWordData), HUGE_VAL); + ecl_kw_get_data_as_double(eclKeyWordData, valuesAllCells.data()); + + newPropertyData[0].resize(activeCellInfo->globalActiveCellCount(), HUGE_VAL); + std::vector& valuesActiveCells = newPropertyData[0]; + + size_t acIdx = 0; + for (size_t gcIdx = 0; gcIdx < activeCellInfo->globalCellCount(); gcIdx++) + { + size_t activeCellResultIndex = activeCellInfo->cellResultIndex(gcIdx); + if (activeCellResultIndex != cvf::UNDEFINED_SIZE_T) + { + valuesActiveCells[activeCellResultIndex] = valuesAllCells[gcIdx]; + } + } + } + else + { + newPropertyData[0].resize(ecl_kw_get_size(eclKeyWordData), HUGE_VAL); + ecl_kw_get_data_as_double(eclKeyWordData, newPropertyData[0].data()); + } +} + + //-------------------------------------------------------------------------------------------------- /// Constructor //-------------------------------------------------------------------------------------------------- @@ -197,9 +264,9 @@ bool RifEclipseInputFileTools::openGridFile(const QString& fileName, RigCaseData //-------------------------------------------------------------------------------------------------- /// Read known properties from the input file //-------------------------------------------------------------------------------------------------- -std::map RifEclipseInputFileTools::readProperties(const QString &fileName, RigCaseData *reservoir) +std::map RifEclipseInputFileTools::readProperties(const QString &fileName, RigCaseData* caseData) { - CVF_ASSERT(reservoir); + CVF_ASSERT(caseData); std::set knownKeywordSet; { @@ -231,19 +298,18 @@ std::map RifEclipseInputFileTools::readProperties(const QStri if (knownKeywordSet.count(fileKeywords[i].keyword)) { fseek(gridFilePointer, fileKeywords[i].filePos, SEEK_SET); - ecl_kw_type* eclKeyWordData = ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false , ECL_FLOAT_TYPE); - if (eclKeyWordData) + ecl_kw_type* eclipseKeywordData = ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false , ECL_FLOAT_TYPE); + if (eclipseKeywordData) { - QString newResultName = reservoir->results(RifReaderInterface::MATRIX_RESULTS)->makeResultNameUnique(fileKeywords[i].keyword); - - size_t resultIndex = reservoir->results(RifReaderInterface::MATRIX_RESULTS)->addEmptyScalarResult(RimDefines::INPUT_PROPERTY, newResultName, false); // Should really merge with inputProperty object information because we need to use PropertyName, and not keyword + QString newResultName = caseData->results(RifReaderInterface::MATRIX_RESULTS)->makeResultNameUnique(fileKeywords[i].keyword); - std::vector< std::vector >& newPropertyData = reservoir->results(RifReaderInterface::MATRIX_RESULTS)->cellScalarResults(resultIndex); - newPropertyData.push_back(std::vector()); - newPropertyData[0].resize(ecl_kw_get_size(eclKeyWordData), HUGE_VAL); - ecl_kw_get_data_as_double(eclKeyWordData, newPropertyData[0].data()); + size_t resultIndex = findOrCreateResult(newResultName, caseData); + if (resultIndex != cvf::UNDEFINED_SIZE_T) + { + readDoubleValues(caseData, resultIndex, eclipseKeywordData); + } - ecl_kw_free(eclKeyWordData); + ecl_kw_free(eclipseKeywordData); newResults[newResultName] = fileKeywords[i].keyword; } } @@ -300,30 +366,24 @@ void RifEclipseInputFileTools::findKeywordsOnFile(const QString &fileName, std:: /// Reads the property data requested into the \a reservoir, overwriting any previous /// propeties with the same name. //-------------------------------------------------------------------------------------------------- -bool RifEclipseInputFileTools::readProperty(const QString& fileName, RigCaseData* eclipseCase, const QString& eclipseKeyWord, const QString& resultName) +bool RifEclipseInputFileTools::readProperty(const QString& fileName, RigCaseData* caseData, const QString& eclipseKeyWord, const QString& resultName) { - CVF_ASSERT(eclipseCase); + CVF_ASSERT(caseData); FILE* filePointer = util_fopen(fileName.toLatin1().data(), "r"); if (!filePointer) return false; - ecl_kw_type* eclKeyWordData = ecl_kw_fscanf_alloc_grdecl_dynamic__( filePointer , eclipseKeyWord.toLatin1().data() , false , ECL_FLOAT_TYPE); + ecl_kw_type* eclipseKeywordData = ecl_kw_fscanf_alloc_grdecl_dynamic__( filePointer , eclipseKeyWord.toLatin1().data() , false , ECL_FLOAT_TYPE); bool isOk = false; - if (eclKeyWordData) + if (eclipseKeywordData) { - QString newResultName = resultName; - size_t resultIndex = eclipseCase->results(RifReaderInterface::MATRIX_RESULTS)->findScalarResultIndex(newResultName); - if (resultIndex == cvf::UNDEFINED_SIZE_T) + size_t resultIndex = findOrCreateResult(resultName, caseData); + if (resultIndex != cvf::UNDEFINED_SIZE_T) { - resultIndex = eclipseCase->results(RifReaderInterface::MATRIX_RESULTS)->addEmptyScalarResult(RimDefines::INPUT_PROPERTY, newResultName, false); + isOk = readDoubleValues(caseData, resultIndex, eclipseKeywordData); } - std::vector< std::vector >& newPropertyData = eclipseCase->results(RifReaderInterface::MATRIX_RESULTS)->cellScalarResults(resultIndex); - newPropertyData.resize(1); - newPropertyData[0].resize(ecl_kw_get_size(eclKeyWordData), HUGE_VAL); - ecl_kw_get_data_as_double(eclKeyWordData, newPropertyData[0].data()); - isOk = true; - ecl_kw_free(eclKeyWordData); + ecl_kw_free(eclipseKeywordData); } util_fclose(filePointer); @@ -535,31 +595,25 @@ void RifEclipseInputFileTools::findGridKeywordPositions(const std::vector< RifKe //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RifEclipseInputFileTools::readPropertyAtFilePosition(const QString& fileName, RigCaseData* eclipseCase, const QString& eclipseKeyWord, qint64 filePos, const QString& resultName) +bool RifEclipseInputFileTools::readPropertyAtFilePosition(const QString& fileName, RigCaseData* caseData, const QString& eclipseKeyWord, qint64 filePos, const QString& resultName) { - CVF_ASSERT(eclipseCase); + CVF_ASSERT(caseData); FILE* filePointer = util_fopen(fileName.toLatin1().data(), "r"); if (!filePointer) return false; fseek(filePointer, filePos, SEEK_SET); - ecl_kw_type* eclKeyWordData = ecl_kw_fscanf_alloc_current_grdecl__(filePointer, false , ECL_FLOAT_TYPE); + ecl_kw_type* eclipseKeywordData = ecl_kw_fscanf_alloc_current_grdecl__(filePointer, false , ECL_FLOAT_TYPE); bool isOk = false; - if (eclKeyWordData) + if (eclipseKeywordData) { - QString newResultName = resultName; - size_t resultIndex = eclipseCase->results(RifReaderInterface::MATRIX_RESULTS)->findScalarResultIndex(newResultName); - if (resultIndex == cvf::UNDEFINED_SIZE_T) + size_t resultIndex = findOrCreateResult(resultName, caseData); + if (resultIndex != cvf::UNDEFINED_SIZE_T) { - resultIndex = eclipseCase->results(RifReaderInterface::MATRIX_RESULTS)->addEmptyScalarResult(RimDefines::INPUT_PROPERTY, newResultName, false); + isOk = readDoubleValues(caseData, resultIndex, eclipseKeywordData); } - std::vector< std::vector >& newPropertyData = eclipseCase->results(RifReaderInterface::MATRIX_RESULTS)->cellScalarResults(resultIndex); - newPropertyData.resize(1); - newPropertyData[0].resize(ecl_kw_get_size(eclKeyWordData), HUGE_VAL); - ecl_kw_get_data_as_double(eclKeyWordData, newPropertyData[0].data()); - isOk = true; - ecl_kw_free(eclKeyWordData); + ecl_kw_free(eclipseKeywordData); } util_fclose(filePointer); @@ -671,13 +725,13 @@ qint64 RifEclipseInputFileTools::findKeyword(const QString& keyword, QFile& file do { line = file.readLine(); + line = line.trimmed(); + if (line.startsWith("--", Qt::CaseInsensitive)) { continue; } - line = line.trimmed(); - if (line.startsWith(keyword, Qt::CaseInsensitive)) { return file.pos(); @@ -706,6 +760,8 @@ bool RifEclipseInputFileTools::readFaultsAndParseIncludeStatementsRecursively(QF do { line = file.readLine(); + line = line.trimmed(); + if (line.startsWith("--", Qt::CaseInsensitive)) { continue; @@ -720,14 +776,19 @@ bool RifEclipseInputFileTools::readFaultsAndParseIncludeStatementsRecursively(QF return false; } - - line = line.trimmed(); if (line.startsWith(includeKeyword, Qt::CaseInsensitive)) { - QString nextLine = file.readLine(); + line = file.readLine(); + line = line.trimmed(); + + while (line.startsWith("--", Qt::CaseInsensitive)) + { + line = file.readLine(); + line = line.trimmed(); + } - int firstQuote = nextLine.indexOf("'"); - int lastQuote = nextLine.lastIndexOf("'"); + int firstQuote = line.indexOf("'"); + int lastQuote = line.lastIndexOf("'"); if (!(firstQuote < 0 || lastQuote < 0 || firstQuote == lastQuote)) { @@ -738,7 +799,7 @@ bool RifEclipseInputFileTools::readFaultsAndParseIncludeStatementsRecursively(QF } // Read include file name, and both relative and absolute path is supported - QString includeFilename = nextLine.mid(firstQuote + 1, lastQuote - firstQuote - 1); + QString includeFilename = line.mid(firstQuote + 1, lastQuote - firstQuote - 1); QFileInfo fi(currentFileFolder, includeFilename); if (fi.exists()) { diff --git a/ApplicationCode/FileInterface/RifReaderMockModel.cpp b/ApplicationCode/FileInterface/RifReaderMockModel.cpp index f03a79e40f..64507ebc8d 100644 --- a/ApplicationCode/FileInterface/RifReaderMockModel.cpp +++ b/ApplicationCode/FileInterface/RifReaderMockModel.cpp @@ -175,3 +175,11 @@ void RifReaderMockModel::populateReservoir(RigCaseData* eclipseCase) m_reservoirBuilder.populateReservoir(eclipseCase); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifReaderMockModel::enableWellData(bool enableWellData) +{ + m_reservoirBuilder.enableWellData(enableWellData); +} + diff --git a/ApplicationCode/FileInterface/RifReaderMockModel.h b/ApplicationCode/FileInterface/RifReaderMockModel.h index 0237381bbe..3acd5a7c7b 100644 --- a/ApplicationCode/FileInterface/RifReaderMockModel.h +++ b/ApplicationCode/FileInterface/RifReaderMockModel.h @@ -30,6 +30,7 @@ class RifReaderMockModel : public RifReaderInterface void setWorldCoordinates(cvf::Vec3d minWorldCoordinate, cvf::Vec3d maxWorldCoordinate); void setGridPointDimensions(const cvf::Vec3st& gridPointDimensions); void setResultInfo(size_t resultCount, size_t timeStepCount); + void enableWellData(bool enableWellData); void addLocalGridRefinement(const cvf::Vec3st& minCellPosition, const cvf::Vec3st& maxCellPosition, const cvf::Vec3st& singleCellRefinementFactors); diff --git a/ApplicationCode/ModelVisualization/CMakeLists_files.cmake b/ApplicationCode/ModelVisualization/CMakeLists_files.cmake index 6b03dc5a69..02509f21c9 100644 --- a/ApplicationCode/ModelVisualization/CMakeLists_files.cmake +++ b/ApplicationCode/ModelVisualization/CMakeLists_files.cmake @@ -11,6 +11,7 @@ ${CEE_CURRENT_LIST_DIR}RivFaultPartMgr.h ${CEE_CURRENT_LIST_DIR}RivFaultGeometryGenerator.h ${CEE_CURRENT_LIST_DIR}RivNNCGeometryGenerator.h ${CEE_CURRENT_LIST_DIR}RivGridPartMgr.h +${CEE_CURRENT_LIST_DIR}RivTernarySaturationOverlayItem.h ${CEE_CURRENT_LIST_DIR}RivReservoirPartMgr.h ${CEE_CURRENT_LIST_DIR}RivReservoirViewPartMgr.h ${CEE_CURRENT_LIST_DIR}RivPipeGeometryGenerator.h @@ -27,9 +28,10 @@ set (SOURCE_GROUP_SOURCE_FILES ${CEE_CURRENT_LIST_DIR}RivCellEdgeEffectGenerator.cpp ${CEE_CURRENT_LIST_DIR}RivColorTableArray.cpp ${CEE_CURRENT_LIST_DIR}RivFaultPartMgr.cpp -${CEE_CURRENT_LIST_DIR}RivFaultGeometryGenerator.cpp ${CEE_CURRENT_LIST_DIR}RivNNCGeometryGenerator.cpp +${CEE_CURRENT_LIST_DIR}RivFaultGeometryGenerator.cpp ${CEE_CURRENT_LIST_DIR}RivGridPartMgr.cpp +${CEE_CURRENT_LIST_DIR}RivTernarySaturationOverlayItem.cpp ${CEE_CURRENT_LIST_DIR}RivReservoirFaultsPartMgr.cpp ${CEE_CURRENT_LIST_DIR}RivReservoirPartMgr.cpp ${CEE_CURRENT_LIST_DIR}RivReservoirViewPartMgr.cpp diff --git a/ApplicationCode/ModelVisualization/RivFaultPartMgr.cpp b/ApplicationCode/ModelVisualization/RivFaultPartMgr.cpp index 1486a69ce4..e2df00d265 100644 --- a/ApplicationCode/ModelVisualization/RivFaultPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivFaultPartMgr.cpp @@ -105,6 +105,7 @@ void RivFaultPartMgr::updateCellResultColor(size_t timeStepIndex, RimResultSlot* updateNNCColors(cellResultSlot); + size_t scalarSetIndex = cellResultSlot->gridScalarIndex(); const cvf::ScalarMapper* mapper = cellResultSlot->legendConfig()->scalarMapper(); @@ -117,12 +118,19 @@ void RivFaultPartMgr::updateCellResultColor(size_t timeStepIndex, RimResultSlot* RigCaseData* eclipseCase = cellResultSlot->reservoirView()->eclipseCase()->reservoirData(); cvf::ref dataAccessObject = eclipseCase->dataAccessObject(m_grid.p(), porosityModel, resTimeStepIdx, scalarSetIndex); - if (dataAccessObject.isNull()) return; - // Faults if (m_nativeFaultFaces.notNull()) { - if (cellResultSlot->resultVariable().compare(RimDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0) + cvf::ref surfaceFacesColorArray; + if (cellResultSlot->isTernarySaturationSelected()) + { + surfaceFacesColorArray = new cvf::Color3ubArray; + + const std::vector& quadsToGridCells = m_nativeFaultGenerator->quadToGridCellIndices(); + + RivTransmissibilityColorMapper::updateTernarySaturationColorArray(timeStepIndex, cellResultSlot, m_grid.p(), surfaceFacesColorArray.p(), quadsToGridCells); + } + else if (cellResultSlot->resultVariable().compare(RimDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0) { const std::vector& quadsToFaceTypes = m_nativeFaultGenerator->quadToFace(); const std::vector& quadsToGridCells = m_nativeFaultGenerator->quadToGridCellIndices(); @@ -132,7 +140,12 @@ void RivFaultPartMgr::updateCellResultColor(size_t timeStepIndex, RimResultSlot* } else { + if (dataAccessObject.isNull()) + { + return; + } m_nativeFaultGenerator->textureCoordinates(m_nativeFaultFacesTextureCoords.p(), dataAccessObject.p(), mapper); + } if (m_opacityLevel < 1.0f ) @@ -159,16 +172,41 @@ void RivFaultPartMgr::updateCellResultColor(size_t timeStepIndex, RimResultSlot* } cvf::DrawableGeo* dg = dynamic_cast(m_nativeFaultFaces->drawable()); - if (dg) dg->setTextureCoordArray(m_nativeFaultFacesTextureCoords.p()); + if (surfaceFacesColorArray.notNull()) + { + if (dg) + { + dg->setColorArray(surfaceFacesColorArray.p()); + } + + cvf::ref perVertexColorEffect = RivGridPartMgr::createPerVertexColoringEffect(m_opacityLevel); + m_nativeFaultFaces->setEffect(perVertexColorEffect.p()); - cvf::ref scalarEffect = cellResultEffect(mapper, caf::PO_1); - m_nativeFaultFaces->setEffect(scalarEffect.p()); + m_nativeFaultFaces->setPriority(100); + } + else + { + if (dg) dg->setTextureCoordArray(m_nativeFaultFacesTextureCoords.p()); + + cvf::ref scalarEffect = cellResultEffect(mapper, caf::PO_1); + m_nativeFaultFaces->setEffect(scalarEffect.p()); + } } if (m_oppositeFaultFaces.notNull()) { - if (cellResultSlot->resultVariable().compare(RimDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0) + cvf::ref surfaceFacesColorArray; + + if (cellResultSlot->isTernarySaturationSelected()) + { + surfaceFacesColorArray = new cvf::Color3ubArray; + + const std::vector& quadsToGridCells = m_oppositeFaultGenerator->quadToGridCellIndices(); + + RivTransmissibilityColorMapper::updateTernarySaturationColorArray(timeStepIndex, cellResultSlot, m_grid.p(), surfaceFacesColorArray.p(), quadsToGridCells); + } + else if (cellResultSlot->resultVariable().compare(RimDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0) { const std::vector& quadsToFaceTypes = m_oppositeFaultGenerator->quadToFace(); const std::vector& quadsToGridCells = m_oppositeFaultGenerator->quadToGridCellIndices(); @@ -178,6 +216,11 @@ void RivFaultPartMgr::updateCellResultColor(size_t timeStepIndex, RimResultSlot* } else { + if (dataAccessObject.isNull()) + { + return; + } + m_oppositeFaultGenerator->textureCoordinates(m_oppositeFaultFacesTextureCoords.p(), dataAccessObject.p(), mapper); } @@ -205,12 +248,27 @@ void RivFaultPartMgr::updateCellResultColor(size_t timeStepIndex, RimResultSlot* } cvf::DrawableGeo* dg = dynamic_cast(m_oppositeFaultFaces->drawable()); - if (dg) dg->setTextureCoordArray(m_oppositeFaultFacesTextureCoords.p()); + if (surfaceFacesColorArray.notNull()) + { + if (dg) + { + dg->setColorArray(surfaceFacesColorArray.p()); + } + + cvf::ref perVertexColorEffect = RivGridPartMgr::createPerVertexColoringEffect(m_opacityLevel); + m_oppositeFaultFaces->setEffect(perVertexColorEffect.p()); + + m_oppositeFaultFaces->setPriority(100); + } + else + { + if (dg) dg->setTextureCoordArray(m_oppositeFaultFacesTextureCoords.p()); - // Use a different offset than native fault faces to avoid z-fighting - cvf::ref scalarEffect = cellResultEffect(mapper, caf::PO_2); + // Use a different offset than native fault faces to avoid z-fighting + cvf::ref scalarEffect = cellResultEffect(mapper, caf::PO_2); - m_oppositeFaultFaces->setEffect(scalarEffect.p()); + m_oppositeFaultFaces->setEffect(scalarEffect.p()); + } } } @@ -223,15 +281,15 @@ void RivFaultPartMgr::updateCellEdgeResultColor(size_t timeStepIndex, RimResultS } +const int priFaultGeo = 1; +const int priNncGeo = 2; +const int priMesh = 3; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivFaultPartMgr::generatePartGeometry() { - const int priFaultGeo = 1; - const int priNncGeo = 2; - const int priMesh = 3; bool useBufferObjects = true; // Surface geometry @@ -418,13 +476,20 @@ void RivFaultPartMgr::updatePartEffect() if (m_opacityLevel < 1.0f) { - // Must be fixed since currently fault drawing relies on internal priorities of the parts - CVF_FAIL_MSG("Not implemented"); - // Set priority to make sure this transparent geometry are rendered last - if (m_nativeFaultFaces.notNull()) m_nativeFaultFaces->setPriority(100); - if (m_oppositeFaultFaces.notNull()) m_oppositeFaultFaces->setPriority(100); - if (m_NNCFaces.notNull()) m_NNCFaces->setPriority(100); + if (m_nativeFaultFaces.notNull()) m_nativeFaultFaces->setPriority(100 + priFaultGeo); + if (m_oppositeFaultFaces.notNull()) m_oppositeFaultFaces->setPriority(100 + priFaultGeo); + if (m_NNCFaces.notNull()) m_NNCFaces->setPriority(100 + priNncGeo); + + if (m_nativeFaultGridLines.notNull()) + { + m_nativeFaultGridLines->setPriority(100 + priMesh); + } + + if (m_oppositeFaultGridLines.notNull()) + { + m_oppositeFaultGridLines->setPriority(100 + priMesh); + } } } diff --git a/ApplicationCode/ModelVisualization/RivFaultPartMgr.h b/ApplicationCode/ModelVisualization/RivFaultPartMgr.h index 139c6b57dd..d4a01e8736 100644 --- a/ApplicationCode/ModelVisualization/RivFaultPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivFaultPartMgr.h @@ -53,6 +53,7 @@ class RivFaultPartMgr : public cvf::Object void setCellVisibility(cvf::UByteArray* cellVisibilities); void applySingleColorEffect(); + void setOpacityLevel(float opacity) { m_opacityLevel = opacity; } void updateCellResultColor(size_t timeStepIndex, RimResultSlot* cellResultSlot); void updateCellEdgeResultColor(size_t timeStepIndex, RimResultSlot* cellResultSlot, RimCellEdgeResultSlot* cellEdgeResultSlot); diff --git a/ApplicationCode/ModelVisualization/RivGridPartMgr.cpp b/ApplicationCode/ModelVisualization/RivGridPartMgr.cpp index 7da5466ff8..ddf67713c6 100644 --- a/ApplicationCode/ModelVisualization/RivGridPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivGridPartMgr.cpp @@ -18,33 +18,40 @@ #include "RivGridPartMgr.h" -#include "cvfPart.h" + #include "cafEffectGenerator.h" -#include "cvfStructGrid.h" +#include "cafPdmFieldCvfColor.h" +#include "cafPdmFieldCvfMat4d.h" +#include "cafProgressInfo.h" #include "cvfDrawableGeo.h" +#include "cvfMath.h" #include "cvfModelBasicList.h" -#include "RivCellEdgeEffectGenerator.h" -#include "RimReservoirView.h" -#include "RimResultSlot.h" -#include "RimCellEdgeResultSlot.h" -#include "RigCaseCellResultsData.h" -#include "RigCaseData.h" +#include "cvfPart.h" +#include "cvfRenderStateBlending.h" +#include "cvfRenderStatePolygonOffset.h" +#include "cvfRenderState_FF.h" +#include "cvfShaderProgram.h" +#include "cvfShaderProgramGenerator.h" +#include "cvfShaderSourceProvider.h" +#include "cvfShaderSourceRepository.h" +#include "cvfStructGrid.h" +#include "cvfUniform.h" + #include "RiaApplication.h" #include "RiaPreferences.h" - +#include "RigCaseCellResultsData.h" +#include "RigCaseData.h" #include "RimCase.h" -#include "RimWellCollection.h" -#include "cafPdmFieldCvfMat4d.h" -#include "cafPdmFieldCvfColor.h" -#include "RimCellRangeFilterCollection.h" -#include "RimCellPropertyFilterCollection.h" -#include "Rim3dOverlayInfoConfig.h" +#include "RimCellEdgeResultSlot.h" #include "RimReservoirCellResultsCacher.h" +#include "RimReservoirView.h" +#include "RimResultSlot.h" +#include "RimTernaryLegendConfig.h" +#include "RimWellCollection.h" +#include "RivCellEdgeEffectGenerator.h" #include "RivSourceInfo.h" - - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -250,15 +257,23 @@ void RivGridPartMgr::updateCellResultColor(size_t timeStepIndex, RimResultSlot* { CVF_ASSERT(cellResultSlot); - const cvf::ScalarMapper* mapper = cellResultSlot->legendConfig()->scalarMapper(); RigCaseData* eclipseCase = cellResultSlot->reservoirView()->eclipseCase()->reservoirData(); - + cvf::ref surfaceFacesColorArray; + // Outer surface if (m_surfaceFaces.notNull()) { - if (cellResultSlot->resultVariable().compare(RimDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0) + if (cellResultSlot->isTernarySaturationSelected()) + { + surfaceFacesColorArray = new cvf::Color3ubArray; + + const std::vector& quadsToGridCells = m_surfaceGenerator.quadToGridCellIndices(); + + RivTransmissibilityColorMapper::updateTernarySaturationColorArray(timeStepIndex, cellResultSlot, m_grid.p(), surfaceFacesColorArray.p(), quadsToGridCells); + } + else if (cellResultSlot->resultVariable().compare(RimDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0) { const std::vector& quadsToFaceTypes = m_surfaceGenerator.quadToFace(); const std::vector& quadsToGridCells = m_surfaceGenerator.quadToGridCellIndices(); @@ -309,16 +324,34 @@ void RivGridPartMgr::updateCellResultColor(size_t timeStepIndex, RimResultSlot* } cvf::DrawableGeo* dg = dynamic_cast(m_surfaceFaces->drawable()); - if (dg) dg->setTextureCoordArray(m_surfaceFacesTextureCoords.p()); + if (surfaceFacesColorArray.notNull()) + { + if (dg) + { + dg->setColorArray(surfaceFacesColorArray.p()); + } - caf::PolygonOffset polygonOffset = caf::PO_1; - caf::ScalarMapperEffectGenerator scalarEffgen(mapper, polygonOffset); + cvf::ref perVertexColorEffect = RivGridPartMgr::createPerVertexColoringEffect(m_opacityLevel); + m_surfaceFaces->setEffect(perVertexColorEffect.p()); - scalarEffgen.setOpacityLevel(m_opacityLevel); + m_surfaceFaces->setPriority(100); + } + else + { + if (dg) + { + dg->setTextureCoordArray(m_surfaceFacesTextureCoords.p()); + } - cvf::ref scalarEffect = scalarEffgen.generateEffect(); + caf::PolygonOffset polygonOffset = caf::PO_1; + caf::ScalarMapperEffectGenerator scalarEffgen(mapper, polygonOffset); + + scalarEffgen.setOpacityLevel(m_opacityLevel); + + cvf::ref scalarEffect = scalarEffgen.generateEffect(); - m_surfaceFaces->setEffect(scalarEffect.p()); + m_surfaceFaces->setEffect(scalarEffect.p()); + } } // Faults @@ -433,6 +466,53 @@ RivGridPartMgr::~RivGridPartMgr() #endif } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RivGridPartMgr::createPerVertexColoringEffect(float opacity) +{ + cvf::ref colorArrayEffect = new cvf::Effect; + + if (RiaApplication::instance()->useShaders()) + { + cvf::ShaderProgramGenerator gen("PerVertexColor", cvf::ShaderSourceProvider::instance()); + gen.addVertexCode(cvf::ShaderSourceRepository::vs_Standard); + gen.addFragmentCode(cvf::ShaderSourceRepository::src_VaryingColorGlobalAlpha); + gen.addFragmentCode(caf::CommonShaderSources::light_AmbientDiffuse()); + gen.addFragmentCode(cvf::ShaderSourceRepository::fs_Standard); + + cvf::ref m_shaderProg = gen.generate(); + m_shaderProg->setDefaultUniform(new cvf::UniformFloat("u_alpha", opacity)); + + colorArrayEffect->setShaderProgram(m_shaderProg.p()); + } + else + { + cvf::ref mat = new cvf::RenderStateMaterial_FF(cvf::Color3::BLUE); + mat->setAlpha(opacity); + mat->enableColorMaterial(true); + colorArrayEffect->setRenderState(mat.p()); + + cvf::ref lighting = new cvf::RenderStateLighting_FF; + lighting->enableTwoSided(true); + colorArrayEffect->setRenderState(lighting.p()); + } + + // Simple transparency + if (opacity < 1.0f) + { + cvf::ref blender = new cvf::RenderStateBlending; + blender->configureTransparencyBlending(); + colorArrayEffect->setRenderState(blender.p()); + } + + caf::PolygonOffset polygonOffset = caf::PO_1; + cvf::ref polyOffset = caf::EffectGenerator::createAndConfigurePolygonOffsetRenderState(polygonOffset); + colorArrayEffect->setRenderState(polyOffset.p()); + + return colorArrayEffect; +} + //-------------------------------------------------------------------------------------------------- /// @@ -487,7 +567,7 @@ void RivTransmissibilityColorMapper::updateCombinedTransmissibilityTextureCoordi size_t i, j, k, neighborGridCellIdx; grid->ijkFromCellIndex(quadsToGridCells[idx], &i, &j, &k); - if(grid->cellIJKNeighbor(i, j, k, cvf::StructGridInterface::POS_I, &neighborGridCellIdx)) + if(grid->cellIJKNeighbor(i, j, k, cvf::StructGridInterface::NEG_I, &neighborGridCellIdx)) { cellScalarValue = dataAccessObjectTranX->cellScalar(neighborGridCellIdx); } @@ -501,7 +581,7 @@ void RivTransmissibilityColorMapper::updateCombinedTransmissibilityTextureCoordi size_t i, j, k, neighborGridCellIdx; grid->ijkFromCellIndex(quadsToGridCells[idx], &i, &j, &k); - if(grid->cellIJKNeighbor(i, j, k, cvf::StructGridInterface::POS_J, &neighborGridCellIdx)) + if(grid->cellIJKNeighbor(i, j, k, cvf::StructGridInterface::NEG_J, &neighborGridCellIdx)) { cellScalarValue = dataAccessObjectTranY->cellScalar(neighborGridCellIdx); } @@ -515,7 +595,7 @@ void RivTransmissibilityColorMapper::updateCombinedTransmissibilityTextureCoordi size_t i, j, k, neighborGridCellIdx; grid->ijkFromCellIndex(quadsToGridCells[idx], &i, &j, &k); - if(grid->cellIJKNeighbor(i, j, k, cvf::StructGridInterface::POS_K, &neighborGridCellIdx)) + if(grid->cellIJKNeighbor(i, j, k, cvf::StructGridInterface::NEG_K, &neighborGridCellIdx)) { cellScalarValue = dataAccessObjectTranZ->cellScalar(neighborGridCellIdx); } @@ -535,3 +615,121 @@ void RivTransmissibilityColorMapper::updateCombinedTransmissibilityTextureCoordi } } + + +//-------------------------------------------------------------------------------------------------- +/// Helper class used to provide zero for all cells +/// This way we can avoid to test if a StructGridScalarDataAccess object is valid before reading out the value. +//-------------------------------------------------------------------------------------------------- +class ScalarDataAccessZeroForAllCells : public cvf::StructGridScalarDataAccess +{ +public: + virtual double cellScalar(size_t cellIndex) const + { + return 0.0; + } + virtual void setCellScalar(size_t cellIndex, double value) + { + } +}; + + +//-------------------------------------------------------------------------------------------------- +/// Creates and assigns a ternary saturation color for all four vertices of a quad representing a cell face +/// +/// Loads ternary saturation results SOIL, SWAT and SGAS +/// If any of these are not present, the values for a missing component is set to 0.0 +//-------------------------------------------------------------------------------------------------- +void RivTransmissibilityColorMapper::updateTernarySaturationColorArray(size_t timeStepIndex, RimResultSlot* cellResultSlot, const RigGridBase* grid, cvf::Color3ubArray* colorArray, const std::vector& quadsToGridCells) +{ + RimReservoirCellResultsStorage* gridCellResults = cellResultSlot->currentGridCellResults(); + if (!gridCellResults) return; + + RigCaseData* eclipseCase = cellResultSlot->reservoirView()->eclipseCase()->reservoirData(); + if (!eclipseCase) return; + + size_t soilScalarSetIndex = gridCellResults->findOrLoadScalarResult(RimDefines::DYNAMIC_NATIVE, "SOIL"); + size_t sgasScalarSetIndex = gridCellResults->findOrLoadScalarResult(RimDefines::DYNAMIC_NATIVE, "SGAS"); + size_t swatScalarSetIndex = gridCellResults->findOrLoadScalarResult(RimDefines::DYNAMIC_NATIVE, "SWAT"); + + RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultSlot->porosityModel()); + + double soilMin = 0.0; + double soilMax = 1.0; + double sgasMin = 0.0; + double sgasMax = 1.0; + double swatMin = 0.0; + double swatMax = 1.0; + + cellResultSlot->ternaryLegendConfig()->ternaryRanges(soilMin, soilMax, sgasMin, sgasMax, swatMin, swatMax); + + cvf::ref dataAccessObjectSoil = eclipseCase->dataAccessObject(grid, porosityModel, timeStepIndex, soilScalarSetIndex); + if (dataAccessObjectSoil.isNull()) + { + dataAccessObjectSoil = new ScalarDataAccessZeroForAllCells; + } + + cvf::ref dataAccessObjectSgas = eclipseCase->dataAccessObject(grid, porosityModel, timeStepIndex, sgasScalarSetIndex); + if (dataAccessObjectSgas.isNull()) + { + dataAccessObjectSgas = new ScalarDataAccessZeroForAllCells; + } + + cvf::ref dataAccessObjectSwat = eclipseCase->dataAccessObject(grid, porosityModel, timeStepIndex, swatScalarSetIndex); + if (dataAccessObjectSwat.isNull()) + { + dataAccessObjectSwat = new ScalarDataAccessZeroForAllCells; + } + + double soilRange = soilMax - soilMin; + double soilFactor = 255.0 / soilRange; + + double sgasRange = sgasMax - sgasMin; + double sgasFactor = 255.0 / sgasRange; + + double swatRange = swatMax - swatMin; + double swatFactor = 255.0 / swatRange; + + size_t numVertices = quadsToGridCells.size()*4; + + colorArray->resize(numVertices); + + cvf::Color3ub ternaryColorByte; + double v, vNormalized; + +#pragma omp parallel for private(ternaryColorByte, v, vNormalized) + for (int idx = 0; idx < static_cast(quadsToGridCells.size()); idx++) + { + size_t gridCellIndex = quadsToGridCells[idx]; + + { + v = dataAccessObjectSgas->cellScalar(gridCellIndex); + vNormalized = (v - sgasMin) * sgasFactor; + + vNormalized = cvf::Math::clamp(vNormalized, 0.0, 255.0); + ternaryColorByte.r() = vNormalized; + } + + { + v = dataAccessObjectSoil->cellScalar(gridCellIndex); + vNormalized = (v - soilMin) * soilFactor; + + vNormalized = cvf::Math::clamp(vNormalized, 0.0, 255.0); + ternaryColorByte.g() = vNormalized; + } + + { + v = dataAccessObjectSwat->cellScalar(gridCellIndex); + vNormalized = (v - swatMin) * swatFactor; + + vNormalized = cvf::Math::clamp(vNormalized, 0.0, 255.0); + ternaryColorByte.b() = vNormalized; + } + + size_t j; + for (j = 0; j < 4; j++) + { + colorArray->set(idx*4 + j, ternaryColorByte); + } + } +} diff --git a/ApplicationCode/ModelVisualization/RivGridPartMgr.h b/ApplicationCode/ModelVisualization/RivGridPartMgr.h index b194f451a1..d205256381 100644 --- a/ApplicationCode/ModelVisualization/RivGridPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivGridPartMgr.h @@ -29,6 +29,7 @@ namespace cvf class ModelBasicList; class Transform; class Part; + class Effect; } class RimResultSlot; @@ -50,6 +51,13 @@ class RivTransmissibilityColorMapper cvf::Vec2fArray* textureCoords, const std::vector& quadsToFaceTypes, const std::vector& quadsToGridCells); + + static void updateTernarySaturationColorArray( + size_t timeStepIndex, + RimResultSlot* cellResultSlot, + const RigGridBase* grid, + cvf::Color3ubArray* colorArray, + const std::vector& quadsToGridCells); }; @@ -73,15 +81,16 @@ class RivGridPartMgr: public cvf::Object void updateCellColor(cvf::Color4f color); void updateCellResultColor(size_t timeStepIndex, RimResultSlot* cellResultSlot); + void updateCellEdgeResultColor(size_t timeStepIndex, RimResultSlot* cellResultSlot, RimCellEdgeResultSlot* cellEdgeResultSlot); void appendPartsToModel(cvf::ModelBasicList* model); + static cvf::ref createPerVertexColoringEffect(float opacity); + private: - void generatePartGeometry(cvf::StructGridGeometryGenerator& geoBuilder, bool faultGeometry); - - + void generatePartGeometry(cvf::StructGridGeometryGenerator& geoBuilder, bool faultGeometry); private: size_t m_gridIdx; diff --git a/ApplicationCode/ModelVisualization/RivReservoirFaultsPartMgr.cpp b/ApplicationCode/ModelVisualization/RivReservoirFaultsPartMgr.cpp index ea0977e82c..edf8642a9c 100644 --- a/ApplicationCode/ModelVisualization/RivReservoirFaultsPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivReservoirFaultsPartMgr.cpp @@ -233,3 +233,14 @@ void RivReservoirFaultsPartMgr::setFaultForceVisibility(bool forceVisibility) m_forceVisibility = forceVisibility; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivReservoirFaultsPartMgr::setOpacityLevel(float opacity) +{ + for (size_t i = 0; i < m_faultParts.size(); i++) + { + m_faultParts[i]->setOpacityLevel(opacity); + } +} + diff --git a/ApplicationCode/ModelVisualization/RivReservoirFaultsPartMgr.h b/ApplicationCode/ModelVisualization/RivReservoirFaultsPartMgr.h index 10ea6e943f..105b20468f 100644 --- a/ApplicationCode/ModelVisualization/RivReservoirFaultsPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivReservoirFaultsPartMgr.h @@ -46,6 +46,7 @@ class RivReservoirFaultsPartMgr : public cvf::Object void setCellVisibility(cvf::UByteArray* cellVisibilities); void setFaultForceVisibility(bool isFilterGenerated); + void setOpacityLevel(float opacity); void applySingleColorEffect(); void updateColors(size_t timeStepIndex, RimResultSlot* cellResultSlot); void updateCellEdgeResultColor(size_t timeStepIndex, RimResultSlot* cellResultSlot, diff --git a/ApplicationCode/ModelVisualization/RivReservoirPartMgr.cpp b/ApplicationCode/ModelVisualization/RivReservoirPartMgr.cpp index 3bce9cdfed..5ac14e77ce 100644 --- a/ApplicationCode/ModelVisualization/RivReservoirPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivReservoirPartMgr.cpp @@ -41,8 +41,11 @@ void RivReservoirPartMgr::clearAndSetReservoir(const RigCaseData* eclipseCase, c m_allGrids.push_back(new RivGridPartMgr(grids[i], i, faultCollection)); } - // Faults read from file are present only on main grid - m_faultsPartMgr = new RivReservoirFaultsPartMgr(eclipseCase->mainGrid(), faultCollection); + if (eclipseCase->mainGrid()) + { + // Faults read from file are present only on main grid + m_faultsPartMgr = new RivReservoirFaultsPartMgr(eclipseCase->mainGrid(), faultCollection); + } } } @@ -98,6 +101,7 @@ void RivReservoirPartMgr::updateCellColor(cvf::Color4f color) if (m_faultsPartMgr.notNull()) { + m_faultsPartMgr->setOpacityLevel(color.a()); m_faultsPartMgr->applySingleColorEffect(); } } diff --git a/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp b/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp index e0dbb2bd02..3f78c6d111 100644 --- a/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp @@ -714,10 +714,12 @@ void RivReservoirViewPartMgr::computePropertyVisibility(cvf::UByteArray* cellVis size_t scalarResultIndex = (*pfIt)->resultDefinition->gridScalarIndex(); + size_t adjustedTimeStepIndex = timeStepIndex; + // Set time step to zero for static results if ((*pfIt)->resultDefinition()->hasStaticResult()) { - timeStepIndex = 0; + adjustedTimeStepIndex = 0; } const RimCellFilter::FilterModeType filterType = (*pfIt)->filterMode(); @@ -725,7 +727,7 @@ void RivReservoirViewPartMgr::computePropertyVisibility(cvf::UByteArray* cellVis RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel((*pfIt)->resultDefinition()->porosityModel()); RigCaseData* eclipseCase = propFilterColl->reservoirView()->eclipseCase()->reservoirData(); - cvf::ref dataAccessObject = eclipseCase->dataAccessObject(grid, porosityModel, timeStepIndex, scalarResultIndex); + cvf::ref dataAccessObject = eclipseCase->dataAccessObject(grid, porosityModel, adjustedTimeStepIndex, scalarResultIndex); CVF_ASSERT(dataAccessObject.notNull()); //#pragma omp parallel for schedule(dynamic) diff --git a/ApplicationCode/ModelVisualization/RivTernarySaturationOverlayItem.cpp b/ApplicationCode/ModelVisualization/RivTernarySaturationOverlayItem.cpp new file mode 100644 index 0000000000..651297c813 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivTernarySaturationOverlayItem.cpp @@ -0,0 +1,222 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA, Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + +#include "cvfBase.h" + +#include "RivTernarySaturationOverlayItem.h" + + +#include "cvfOpenGL.h" +#include "cvfViewport.h" +#include "cvfCamera.h" +#include "cvfTextDrawer.h" +#include "cvfFont.h" +#include "cvfMatrixState.h" + +#include "cvfRenderState_FF.h" +#include "cvfRenderStateDepth.h" +#include "cvfRenderStatePolygonOffset.h" + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivTernarySaturationOverlayItem::RivTernarySaturationOverlayItem(cvf::Font* font) + : m_textColor(cvf::Color3::BLACK), + m_font(font), + m_size(100, 120) +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivTernarySaturationOverlayItem::~RivTernarySaturationOverlayItem() +{ + // Empty destructor to avoid errors with undefined types when cvf::ref's destructor gets called +} + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivTernarySaturationOverlayItem::setAxisLabelsColor(const cvf::Color3f& color) +{ + m_textColor = color; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec2ui RivTernarySaturationOverlayItem::sizeHint() +{ + return m_size; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivTernarySaturationOverlayItem::setSize(const cvf::Vec2ui& size) +{ + m_size = size; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivTernarySaturationOverlayItem::render(cvf::OpenGLContext* oglContext, const cvf::Vec2i& position, const cvf::Vec2ui& size) +{ + render(oglContext, position, size, false); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivTernarySaturationOverlayItem::renderSoftware(cvf::OpenGLContext* oglContext, const cvf::Vec2i& position, const cvf::Vec2ui& size) +{ + render(oglContext, position, size, true); +} + + +//-------------------------------------------------------------------------------------------------- +/// Set up camera/viewport and render +//-------------------------------------------------------------------------------------------------- +void RivTernarySaturationOverlayItem::render(cvf::OpenGLContext* oglContext, const cvf::Vec2i& position, const cvf::Vec2ui& size, bool software) +{ + if (size.x() <= 0 || size.y() <= 0) + { + return; + } + + cvf::Camera camera; + camera.setViewport(position.x(), position.y(), size.x(), size.y()); + camera.setProjectionAsPixelExact2D(); + camera.setViewMatrix(cvf::Mat4d::IDENTITY); + camera.applyOpenGL(); + camera.viewport()->applyOpenGL(oglContext, cvf::Viewport::CLEAR_DEPTH); + + cvf::TextDrawer textDrawer(m_font.p()); + textDrawer.setTextColor(m_textColor); + + textDrawer.addText("SWAT", cvf::Vec2f(0.0, 10.0)); + textDrawer.addText(m_swatRange, cvf::Vec2f(0.0, 0.0)); + + textDrawer.addText("SOIL", cvf::Vec2f(static_cast(size.x() - 25), 10.0)); + + float soilRangePos = static_cast(size.x() - 40); + if (m_soilRange.size() < 6) + { + soilRangePos += 15; + } + textDrawer.addText(m_soilRange, cvf::Vec2f(soilRangePos, 0.0)); + + textDrawer.addText("SGAS", cvf::Vec2f(static_cast( (size.x() / 2) - 17 ), static_cast(size.y() - 10))); + textDrawer.addText(m_sgasRange, cvf::Vec2f(static_cast( (size.x() / 2) - 17 ), static_cast(size.y() - 20))); + + textDrawer.renderSoftware(oglContext, camera); + + renderAxisImmediateMode(oglContext); + + CVF_CHECK_OGL(oglContext); +} + + + +//-------------------------------------------------------------------------------------------------- +/// Draw the axis using immediate mode OpenGL +//-------------------------------------------------------------------------------------------------- +void RivTernarySaturationOverlayItem::renderAxisImmediateMode(cvf::OpenGLContext* oglContext) +{ +#ifdef CVF_OPENGL_ES + CVF_UNUSED(layout); + CVF_FAIL_MSG("Not supported on OpenGL ES"); +#else + + cvf::RenderStateDepth depth(false); + depth.applyOpenGL(oglContext); + + cvf::RenderStateLighting_FF lighting(false); + lighting.applyOpenGL(oglContext); + + cvf::Color3ub colA(cvf::Color3::BLUE); + cvf::Color3ub colB(cvf::Color3::GREEN); + cvf::Color3ub colC(cvf::Color3::RED); + + float lowerBoundY = 20; + float upperBoundY = static_cast(m_size.y() - 20); + + cvf::Vec3f a(0, lowerBoundY, 0); + cvf::Vec3f b(static_cast(m_size.x()), lowerBoundY, 0); + cvf::Vec3f c(static_cast(m_size.x() / 2), upperBoundY, 0); + + + // Draw filled rectangle elements + glBegin(GL_TRIANGLE_FAN); + + glColor3ubv(colA.ptr()); + glVertex3fv(a.ptr()); + + glColor3ubv(colB.ptr()); + glVertex3fv(b.ptr()); + + glColor3ubv(colC.ptr()); + glVertex3fv(c.ptr()); + glVertex3fv(c.ptr()); + glEnd(); + + + // Lines + cvf::Color3ub linesColor(cvf::Color3::WHITE); + glColor3ubv(linesColor.ptr()); + glBegin(GL_LINE_LOOP); + glVertex3fv(a.ptr()); + glVertex3fv(b.ptr()); + glVertex3fv(c.ptr()); + glEnd(); + + cvf::RenderStateDepth resetDepth; + resetDepth.applyOpenGL(oglContext); + + // Reset render states + cvf::RenderStateLighting_FF resetLighting; + resetLighting.applyOpenGL(oglContext); + + CVF_CHECK_OGL(oglContext); +#endif // CVF_OPENGL_ES + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivTernarySaturationOverlayItem::setRangeText(const cvf::String& soilRange, const cvf::String& sgasRange, const cvf::String& swatRange) +{ + m_soilRange = soilRange; + m_sgasRange = sgasRange; + m_swatRange = swatRange; +} + + diff --git a/ApplicationCode/ModelVisualization/RivTernarySaturationOverlayItem.h b/ApplicationCode/ModelVisualization/RivTernarySaturationOverlayItem.h new file mode 100644 index 0000000000..ca145cf496 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivTernarySaturationOverlayItem.h @@ -0,0 +1,68 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA, Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfOverlayItem.h" +#include "cvfMatrix4.h" +#include "cvfColor3.h" +#include "cvfString.h" + +namespace cvf { + +class Font; + +} + +//================================================================================================== +// +// +// +//================================================================================================== +class RivTernarySaturationOverlayItem : public cvf::OverlayItem +{ +public: + RivTernarySaturationOverlayItem(cvf::Font* font); + ~RivTernarySaturationOverlayItem(); + + void setRangeText(const cvf::String& soilRange, const cvf::String& sgasRange, const cvf::String& swatRange); + + virtual cvf::Vec2ui sizeHint(); + + virtual void render(cvf::OpenGLContext* oglContext, const cvf::Vec2i& position, const cvf::Vec2ui& size); + virtual void renderSoftware(cvf::OpenGLContext* oglContext, const cvf::Vec2i& position, const cvf::Vec2ui& size); + + void setSize(const cvf::Vec2ui& size); + + void setAxisLabelsColor(const cvf::Color3f& color); + +private: + void render(cvf::OpenGLContext* oglContext, const cvf::Vec2i& position, const cvf::Vec2ui& size, bool software); + void renderAxisImmediateMode(cvf::OpenGLContext* oglContext); + +private: + cvf::Color3f m_textColor; // Text color + cvf::ref m_font; + + cvf::String m_soilRange; + cvf::String m_sgasRange; + cvf::String m_swatRange; + + cvf::Vec2ui m_size; // Pixel size of draw area +}; + diff --git a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake index d1eba17c50..1b265e3dd2 100644 --- a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake @@ -46,6 +46,8 @@ ${CEE_CURRENT_LIST_DIR}RimCommandObject.h ${CEE_CURRENT_LIST_DIR}RimTools.h ${CEE_CURRENT_LIST_DIR}RimFault.h ${CEE_CURRENT_LIST_DIR}RimFaultCollection.h +${CEE_CURRENT_LIST_DIR}RimMockModelSettings.h +${CEE_CURRENT_LIST_DIR}RimTernaryLegendConfig.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -90,6 +92,8 @@ ${CEE_CURRENT_LIST_DIR}RimCommandObject.cpp ${CEE_CURRENT_LIST_DIR}RimTools.cpp ${CEE_CURRENT_LIST_DIR}RimFault.cpp ${CEE_CURRENT_LIST_DIR}RimFaultCollection.cpp +${CEE_CURRENT_LIST_DIR}RimMockModelSettings.cpp +${CEE_CURRENT_LIST_DIR}RimTernaryLegendConfig.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp index f0d4ac756a..347895c6a1 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp @@ -140,6 +140,11 @@ void Rim3dOverlayInfoConfig::update3DInfo() "Cell count. Total: %2 Active: %3
" "Main Grid I,J,K: %4, %5, %6 Z-Scale: %7
").arg(caseName, totCellCount, activeCellCountText, iSize, jSize, kSize, zScale); + if (m_reservoirView->cellResult()->isTernarySaturationSelected()) + { + infoText += QString("Cell Property: %1 ").arg(propName); + } + if (m_reservoirView->animationMode() && m_reservoirView->cellResult()->hasResult()) { infoText += QString("Cell Property: %1 ").arg(propName); @@ -165,25 +170,29 @@ void Rim3dOverlayInfoConfig::update3DInfo() { if (m_reservoirView->faultCollection()->faultResult() == RimFaultCollection::FAULT_BACK_FACE_CULLING) { - faultMapping = "Show values from cells behind fault"; + faultMapping = "Cells behind fault"; } else if (m_reservoirView->faultCollection()->faultResult() == RimFaultCollection::FAULT_FRONT_FACE_CULLING) { - faultMapping = "Show values from cells in front of fault"; + faultMapping = "Cells in front of fault"; } else { - faultMapping = "Show values from cells in front and behind fault"; + faultMapping = "Cells in front and behind fault"; } } else { - faultMapping = "Show values from cells in front and behind fault"; + faultMapping = "Cells in front and behind fault"; } infoText += QString("Fault results: %1
").arg(faultMapping); } } + else + { + infoText += "
"; + } if (m_reservoirView->animationMode() && m_reservoirView->cellEdgeResult()->hasResult()) @@ -196,7 +205,8 @@ void Rim3dOverlayInfoConfig::update3DInfo() if ( m_reservoirView->cellResult()->hasDynamicResult() || m_reservoirView->propertyFilterCollection()->hasActiveDynamicFilters() - || m_reservoirView->wellCollection()->hasVisibleWellPipes()) + || m_reservoirView->wellCollection()->hasVisibleWellPipes() + || m_reservoirView->cellResult()->isTernarySaturationSelected()) { int currentTimeStep = m_reservoirView->currentTimeStep(); QDateTime date = m_reservoirView->currentGridCellResults()->cellResults()->timeStepDate(0, currentTimeStep); diff --git a/ApplicationCode/ProjectDataModel/RimCellPropertyFilter.cpp b/ApplicationCode/ProjectDataModel/RimCellPropertyFilter.cpp index ea89ebb599..abb2b6d3fc 100644 --- a/ApplicationCode/ProjectDataModel/RimCellPropertyFilter.cpp +++ b/ApplicationCode/ProjectDataModel/RimCellPropertyFilter.cpp @@ -124,7 +124,26 @@ void RimCellPropertyFilter::fieldChangedByUi(const caf::PdmFieldHandle* changedF //-------------------------------------------------------------------------------------------------- QList RimCellPropertyFilter::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) { - return resultDefinition->calculateValueOptions(fieldNeedingOptions, useOptionsOnly); + QList optionItems = resultDefinition->calculateValueOptions(fieldNeedingOptions, useOptionsOnly); + + // Remove ternary from list, as it is not supported to perform filtering on a ternary result + int ternaryIndex = -1; + for (int i = 0; i < optionItems.size(); i++) + { + QString text = optionItems[i].optionUiText; + + if (text.compare(RimDefines::ternarySaturationResultName(), Qt::CaseInsensitive) == 0) + { + ternaryIndex = i; + } + } + + if (ternaryIndex != -1) + { + optionItems.takeAt(ternaryIndex); + } + + return optionItems; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimDefines.h b/ApplicationCode/ProjectDataModel/RimDefines.h index 95313686a3..c55a7b04e4 100644 --- a/ApplicationCode/ProjectDataModel/RimDefines.h +++ b/ApplicationCode/ProjectDataModel/RimDefines.h @@ -41,7 +41,16 @@ class RimDefines static QString undefinedResultName() { return "None"; } static QString undefinedGridFaultName() { return "Undefined grid faults"; } - static QString combinedTransmissibilityResultName() { return "TRANSXYZ"; } + static QString ternarySaturationResultName() { return "TERNARY"; } + + + // Mock model text identifiers + static QString mockModelBasic() { return "Result Mock Debug Model Simple"; } + static QString mockModelBasicWithResults() { return "Result Mock Debug Model With Results"; } + static QString mockModelLargeWithResults() { return "Result Mock Debug Model Large With Results"; } + static QString mockModelCustomized() { return "Result Mock Debug Model Customized"; } + static QString mockModelBasicInputCase() { return "Input Mock Debug Model Simple"; } + }; diff --git a/ApplicationCode/ProjectDataModel/RimFaultCollection.cpp b/ApplicationCode/ProjectDataModel/RimFaultCollection.cpp index 4400f18536..b6a201af09 100644 --- a/ApplicationCode/ProjectDataModel/RimFaultCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimFaultCollection.cpp @@ -73,7 +73,7 @@ RimFaultCollection::RimFaultCollection() CAF_PDM_InitField(&showFaultFaces, "ShowFaultFaces", true, "Show defined faces", "", "", ""); CAF_PDM_InitField(&showOppositeFaultFaces, "ShowOppositeFaultFaces", true, "Show opposite faces", "", "", ""); CAF_PDM_InitField(&showNNCs, "ShowNNCs", false, "Show NNCs", "", "", ""); - CAF_PDM_InitField(&showResultsOnFaults, "ShowResultsOnFaults", false, "Show results on faults", "", "", ""); + CAF_PDM_InitField(&showResultsOnFaults, "ShowResultsOnFaults", true, "Show results on faults", "", "", ""); CAF_PDM_InitField(&showFaultsOutsideFilters,"ShowFaultsOutsideFilters", true, "Show faults outside filters", "", "", ""); CAF_PDM_InitField(&faultResult, "FaultFaceCulling", caf::AppEnum(RimFaultCollection::FAULT_BACK_FACE_CULLING), "Dynamic Face Selection", "", "", ""); @@ -187,7 +187,7 @@ bool faultComparator(const cvf::ref& a, const cvf::ref& b) //-------------------------------------------------------------------------------------------------- void RimFaultCollection::syncronizeFaults() { - if (!(m_reservoirView && m_reservoirView->eclipseCase() && m_reservoirView->eclipseCase()->reservoirData()) ) return; + if (!(m_reservoirView && m_reservoirView->eclipseCase() && m_reservoirView->eclipseCase()->reservoirData() && m_reservoirView->eclipseCase()->reservoirData()->mainGrid()) ) return; cvf::ref partColors = RivColorTableArray::colorTableArray(); diff --git a/ApplicationCode/ProjectDataModel/RimInputCase.cpp b/ApplicationCode/ProjectDataModel/RimInputCase.cpp index ddfa4876fe..e9ab1a607f 100644 --- a/ApplicationCode/ProjectDataModel/RimInputCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimInputCase.cpp @@ -77,7 +77,7 @@ RimInputCase::~RimInputCase() //-------------------------------------------------------------------------------------------------- void RimInputCase::openDataFileSet(const QStringList& fileNames) { - if (fileNames.contains("Input Mock Debug Model Simple")) + if (fileNames.contains(RimDefines::mockModelBasicInputCase())) { cvf::ref readerInterface = this->createMockModel(fileNames[0]); results(RifReaderInterface::MATRIX_RESULTS)->setReaderInterface(readerInterface.p()); @@ -184,7 +184,7 @@ bool RimInputCase::openEclipseGridFile() { cvf::ref readerInterface; - if (m_gridFileName().contains("Input Mock Debug Model Simple")) + if (m_gridFileName().contains(RimDefines::mockModelBasicInputCase())) { readerInterface = this->createMockModel(this->m_gridFileName()); } @@ -377,7 +377,7 @@ cvf::ref RimInputCase::createMockModel(QString modelName) cvf::ref reservoir = new RigCaseData; cvf::ref mockFileInterface = new RifReaderMockModel; - if (modelName == "Input Mock Debug Model Simple") + if (modelName == RimDefines::mockModelBasicInputCase()) { m_gridFileName = modelName; diff --git a/ApplicationCode/ProjectDataModel/RimLegendConfig.cpp b/ApplicationCode/ProjectDataModel/RimLegendConfig.cpp index b71d66fd4b..3cfd96ca48 100644 --- a/ApplicationCode/ProjectDataModel/RimLegendConfig.cpp +++ b/ApplicationCode/ProjectDataModel/RimLegendConfig.cpp @@ -18,27 +18,23 @@ #include "RimLegendConfig.h" -#include "RimReservoirView.h" #include "cafFactory.h" -#include "cafPdmUiLineEditor.h" +#include "cafPdmFieldCvfColor.h" +#include "cafPdmFieldCvfMat4d.h" #include "cafPdmUiComboBoxEditor.h" +#include "cafPdmUiLineEditor.h" -#include "cvfScalarMapperDiscreteLog.h" -#include "cvfScalarMapperContinuousLog.h" -#include "cvfScalarMapperContinuousLinear.h" #include "cvfOverlayScalarMapperLegend.h" +#include "cvfScalarMapperContinuousLinear.h" +#include "cvfScalarMapperContinuousLog.h" #include "cvfScalarMapperDiscreteLinear.h" +#include "cvfScalarMapperDiscreteLog.h" + #include #include "RiaApplication.h" -#include "cafPdmFieldCvfMat4d.h" -#include "cafPdmFieldCvfColor.h" -#include "RimResultSlot.h" -#include "RimCellEdgeResultSlot.h" -#include "RimCellRangeFilterCollection.h" -#include "RimCellPropertyFilterCollection.h" -#include "RimWellCollection.h" -#include "Rim3dOverlayInfoConfig.h" +#include "RimReservoirView.h" + CAF_PDM_SOURCE_INIT(RimLegendConfig, "Legend"); @@ -112,7 +108,7 @@ RimLegendConfig::RimLegendConfig() CAF_PDM_InitField(&m_colorRangeMode, "ColorRangeMode", ColorRangeEnum(NORMAL) , "Colors", "", "", ""); CAF_PDM_InitField(&m_mappingMode, "MappingMode", MappingEnum(LINEAR_CONTINUOUS) , "Mapping", "", "", ""); - CAF_PDM_InitField(&m_rangeMode, "RangeType", caf::AppEnum(AUTOMATIC_ALLTIMESTEPS), "Range type", "", "Switches between automatic and user defined range on the legend", ""); + CAF_PDM_InitField(&m_rangeMode, "RangeType", RangeModeEnum(AUTOMATIC_ALLTIMESTEPS), "Range type", "", "Switches between automatic and user defined range on the legend", ""); CAF_PDM_InitField(&m_userDefinedMaxValue, "UserDefinedMax", 1.0, "Max", "", "Min value of the legend", ""); CAF_PDM_InitField(&m_userDefinedMinValue, "UserDefinedMin", 0.0, "Min", "", "Max value of the legend", ""); CAF_PDM_InitField(&resultVariableName, "ResultVariableUsage", QString(""), "", "", "", ""); @@ -635,16 +631,18 @@ void RimLegendConfig::setClosestToZeroValues(double globalPosClosestToZero, doub //-------------------------------------------------------------------------------------------------- void RimLegendConfig::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { - caf::PdmUiOrdering * formatGr = uiOrdering.addNewGroup("Format"); - formatGr->add(&m_numLevels); - formatGr->add(&m_precision); - formatGr->add(&m_tickNumberFormat); - formatGr->add(&m_colorRangeMode); - - caf::PdmUiOrdering * mappingGr = uiOrdering.addNewGroup("Mapping"); - mappingGr->add(&m_mappingMode); - mappingGr->add(&m_rangeMode); - mappingGr->add(&m_userDefinedMaxValue); - mappingGr->add(&m_userDefinedMinValue); + { + caf::PdmUiOrdering * formatGr = uiOrdering.addNewGroup("Format"); + formatGr->add(&m_numLevels); + formatGr->add(&m_precision); + formatGr->add(&m_tickNumberFormat); + formatGr->add(&m_colorRangeMode); + + caf::PdmUiOrdering * mappingGr = uiOrdering.addNewGroup("Mapping"); + mappingGr->add(&m_mappingMode); + mappingGr->add(&m_rangeMode); + mappingGr->add(&m_userDefinedMaxValue); + mappingGr->add(&m_userDefinedMinValue); + } } diff --git a/ApplicationCode/ProjectDataModel/RimLegendConfig.h b/ApplicationCode/ProjectDataModel/RimLegendConfig.h index f031c1e66d..a8a697601d 100644 --- a/ApplicationCode/ProjectDataModel/RimLegendConfig.h +++ b/ApplicationCode/ProjectDataModel/RimLegendConfig.h @@ -54,12 +54,14 @@ class RimLegendConfig: public caf::PdmObject caf::PdmField resultVariableName; // Used internally to describe the variable this legend setup is used for - enum RangeModeType + enum RangeModeType { AUTOMATIC_ALLTIMESTEPS, AUTOMATIC_CURRENT_TIMESTEP, USER_DEFINED }; + + typedef caf::AppEnum RangeModeEnum; enum ColorRangesType { @@ -94,6 +96,7 @@ class RimLegendConfig: public caf::PdmObject cvf::ScalarMapper* scalarMapper() { return m_currentScalarMapper.p(); } cvf::OverlayScalarMapperLegend* legend() { return m_legend.p(); } + protected: virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); virtual void initAfterRead(); @@ -104,7 +107,6 @@ class RimLegendConfig: public caf::PdmObject cvf::ref interpolateColorArray(const cvf::Color3ubArray& colorArray, cvf::uint targetColorCount); double roundToNumSignificantDigits(double value, double precision); - private: caf::PdmPointer m_reservoirView; @@ -133,7 +135,7 @@ class RimLegendConfig: public caf::PdmObject caf::PdmField m_numLevels; caf::PdmField m_precision; caf::PdmField > m_tickNumberFormat; - caf::PdmField > m_rangeMode; + caf::PdmField m_rangeMode; caf::PdmField m_userDefinedMaxValue; caf::PdmField m_userDefinedMinValue; caf::PdmField > m_colorRangeMode; diff --git a/ApplicationCode/ProjectDataModel/RimMockModelSettings.cpp b/ApplicationCode/ProjectDataModel/RimMockModelSettings.cpp new file mode 100644 index 0000000000..1266629d4e --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimMockModelSettings.cpp @@ -0,0 +1,77 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiaStdInclude.h" + + +#include "RimMockModelSettings.h" + + + + +CAF_PDM_SOURCE_INIT(RimMockModelSettings, "MockModelSettings"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMockModelSettings::RimMockModelSettings() +{ + CAF_PDM_InitObject("Mock Model Settings", "", "", ""); + + CAF_PDM_InitField(&cellCountX, "CellCountX", quint64(100), "Cell Count X", "", "", ""); + CAF_PDM_InitField(&cellCountY, "CellCountY", quint64(100), "Cell Count Y", "", "", ""); + CAF_PDM_InitField(&cellCountZ, "CellCountZ", quint64(10), "Cell Count Z", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&totalCellCount, "TotalCellCount", "Total Cell Count", "", "", ""); + totalCellCount.setUiReadOnly(true); + + CAF_PDM_InitField(&resultCount, "ResultCount", quint64(3), "Result Count", "", "", ""); + CAF_PDM_InitField(&timeStepCount, "TimeStepCount", quint64(10), "Time Step Count", "", "", ""); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMockModelSettings::~RimMockModelSettings() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimMockModelSettings::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +{ + totalCellCount = cellCountX * cellCountY * cellCountZ; + totalCellCount.updateConnectedEditors(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimMockModelSettings::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + caf::PdmUiGroup* gridSizeGroup = uiOrdering.addNewGroup("Grid size"); + gridSizeGroup->add(&cellCountX); + gridSizeGroup->add(&cellCountY); + gridSizeGroup->add(&cellCountZ); + gridSizeGroup->add(&totalCellCount); + + caf::PdmUiGroup* resultGroup = uiOrdering.addNewGroup("Results"); + resultGroup->add(&resultCount); + resultGroup->add(&timeStepCount); +} diff --git a/ApplicationCode/UserInterface/RiuPreferencesDialog.h b/ApplicationCode/ProjectDataModel/RimMockModelSettings.h similarity index 59% rename from ApplicationCode/UserInterface/RiuPreferencesDialog.h rename to ApplicationCode/ProjectDataModel/RimMockModelSettings.h index 3751e108fb..64d1beac66 100644 --- a/ApplicationCode/UserInterface/RiuPreferencesDialog.h +++ b/ApplicationCode/ProjectDataModel/RimMockModelSettings.h @@ -18,32 +18,35 @@ #pragma once -#include - -namespace caf -{ - class PdmObject; - class PdmUiPropertyView; -} +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" //================================================================================================== -// -// -// +/// +/// //================================================================================================== -class RiuPreferencesDialog : public QDialog +class RimMockModelSettings : public caf::PdmObject { - Q_OBJECT - + CAF_PDM_HEADER_INIT; public: - RiuPreferencesDialog(QWidget* parent, caf::PdmObject* object, const QString& windowTitle); -private: - void setupUi(); + RimMockModelSettings(); + virtual ~RimMockModelSettings(); + + caf::PdmField cellCountX; + caf::PdmField cellCountY; + caf::PdmField cellCountZ; + + caf::PdmField totalCellCount; + + caf::PdmField resultCount; + caf::PdmField timeStepCount; + + + virtual void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ); + + virtual void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ); -private: - QString m_windowTitle; - caf::PdmObject* m_pdmObject; - caf::PdmUiPropertyView* m_pdmUiPropertyView; }; diff --git a/ApplicationCode/ProjectDataModel/RimReservoirCellResultsCacher.cpp b/ApplicationCode/ProjectDataModel/RimReservoirCellResultsCacher.cpp index 3d7231630d..9b3357a8e1 100644 --- a/ApplicationCode/ProjectDataModel/RimReservoirCellResultsCacher.cpp +++ b/ApplicationCode/ProjectDataModel/RimReservoirCellResultsCacher.cpp @@ -56,7 +56,7 @@ CAF_PDM_SOURCE_INIT(RimReservoirCellResultsStorage, "ReservoirCellResultStorage" //-------------------------------------------------------------------------------------------------- RimReservoirCellResultsStorage::RimReservoirCellResultsStorage() : m_cellResults(NULL), - m_ownerMainGrid(NULL) + m_ownerMainGrid(NULL) { CAF_PDM_InitObject("Cacher", "", "", ""); @@ -136,7 +136,7 @@ void RimReservoirCellResultsStorage::setupBeforeSave() // If there is no data, we do not store anything for the current result variable // (Even not the metadata, of cause) size_t timestepCount = m_cellResults->cellScalarResults(resInfo[rIdx].m_gridScalarResultIndex).size(); - + if (timestepCount && resInfo[rIdx].m_needsToBeStored) { progInfo.setProgressDescription(resInfo[rIdx].m_resultName); @@ -251,7 +251,7 @@ size_t RimReservoirCellResultsStorage::findOrLoadScalarResultForTimeStep(RimDefi if (soilScalarResultIndex == cvf::UNDEFINED_SIZE_T) { computeSOILForTimeStep(timeStepIndex); - + soilScalarResultIndex = m_cellResults->findScalarResultIndex(type, resultName); return soilScalarResultIndex; } @@ -419,32 +419,22 @@ void RimReservoirCellResultsStorage::computeSOILForTimeStep(size_t timeStepIndex size_t soilResultValueCount = 0; size_t soilTimeStepCount = 0; - std::vector* swatForTimeStep = NULL; - std::vector* sgasForTimeStep = NULL; if (scalarIndexSWAT != cvf::UNDEFINED_SIZE_T) { - swatForTimeStep = &(m_cellResults->cellScalarResults(scalarIndexSWAT, timeStepIndex)); - if (swatForTimeStep->size() == 0) + std::vector& swatForTimeStep = m_cellResults->cellScalarResults(scalarIndexSWAT, timeStepIndex); + if (swatForTimeStep.size() > 0) { - swatForTimeStep = NULL; - } - else - { - soilResultValueCount = swatForTimeStep->size(); + soilResultValueCount = swatForTimeStep.size(); soilTimeStepCount = m_cellResults->infoForEachResultIndex()[scalarIndexSWAT].m_timeStepDates.size(); } } if (scalarIndexSGAS != cvf::UNDEFINED_SIZE_T) { - sgasForTimeStep = &(m_cellResults->cellScalarResults(scalarIndexSGAS, timeStepIndex)); - if (sgasForTimeStep->size() == 0) + std::vector& sgasForTimeStep = m_cellResults->cellScalarResults(scalarIndexSGAS, timeStepIndex); + if (sgasForTimeStep.size() > 0) { - sgasForTimeStep = NULL; - } - else - { - soilResultValueCount = qMax(soilResultValueCount, sgasForTimeStep->size()); + soilResultValueCount = qMax(soilResultValueCount, sgasForTimeStep.size()); size_t sgasTimeStepCount = m_cellResults->infoForEachResultIndex()[scalarIndexSGAS].m_timeStepDates.size(); soilTimeStepCount = qMax(soilTimeStepCount, sgasTimeStepCount); @@ -468,6 +458,28 @@ void RimReservoirCellResultsStorage::computeSOILForTimeStep(size_t timeStepIndex } } + + std::vector* swatForTimeStep = NULL; + std::vector* sgasForTimeStep = NULL; + + if (scalarIndexSWAT != cvf::UNDEFINED_SIZE_T) + { + swatForTimeStep = &(m_cellResults->cellScalarResults(scalarIndexSWAT, timeStepIndex)); + if (swatForTimeStep->size() == 0) + { + swatForTimeStep = NULL; + } + } + + if (scalarIndexSGAS != cvf::UNDEFINED_SIZE_T) + { + sgasForTimeStep = &(m_cellResults->cellScalarResults(scalarIndexSGAS, timeStepIndex)); + if (sgasForTimeStep->size() == 0) + { + sgasForTimeStep = NULL; + } + } + std::vector& soilForTimeStep = m_cellResults->cellScalarResults(soilResultGridIndex, timeStepIndex); #pragma omp parallel for @@ -514,7 +526,7 @@ void RimReservoirCellResultsStorage::computeDepthRelatedResults() if (depthResultGridIndex == cvf::UNDEFINED_SIZE_T) { - depthResultGridIndex = m_cellResults->addStaticScalarResult(RimDefines::STATIC_NATIVE, "DEPTH", false, resultValueCount); + depthResultGridIndex = m_cellResults->addStaticScalarResult(RimDefines::STATIC_NATIVE, "DEPTH", false, resultValueCount); computeDepth = true; } @@ -694,7 +706,7 @@ void RimReservoirCellResultsStorage::setCellResults(RigCaseCellResultsData* cell for (size_t tsIdx = 0; tsIdx < resInfo->m_timeStepDates().size(); ++tsIdx) { std::vector* data = NULL; - + data = &(m_cellResults->cellScalarResults(rIdx, tsIdx)); quint64 cellCount = 0; @@ -760,4 +772,4 @@ RimReservoirCellResultsStorageEntryInfo::RimReservoirCellResultsStorageEntryInfo RimReservoirCellResultsStorageEntryInfo::~RimReservoirCellResultsStorageEntryInfo() { -} +} \ No newline at end of file diff --git a/ApplicationCode/ProjectDataModel/RimReservoirView.cpp b/ApplicationCode/ProjectDataModel/RimReservoirView.cpp index 7c9e6587d4..3438706133 100644 --- a/ApplicationCode/ProjectDataModel/RimReservoirView.cpp +++ b/ApplicationCode/ProjectDataModel/RimReservoirView.cpp @@ -45,6 +45,7 @@ #include "RimCaseCollection.h" #include "RimOilField.h" #include "RimAnalysisModels.h" +#include "RimTernaryLegendConfig.h" #include "RiuMainWindow.h" #include "RigGridBase.h" @@ -74,6 +75,7 @@ #include #include "cafCeetronPlusNavigation.h" #include "RimFaultCollection.h" +#include "RivTernarySaturationOverlayItem.h" namespace caf { @@ -172,8 +174,8 @@ RimReservoirView::RimReservoirView() this->cellResult()->setReservoirView(this); - this->cellResult()->legendConfig()->setReservoirView(this); this->cellResult()->legendConfig()->setPosition(cvf::Vec2ui(10, 120)); + this->cellEdgeResult()->setReservoirView(this); this->cellEdgeResult()->legendConfig()->setReservoirView(this); this->cellEdgeResult()->legendConfig()->setPosition(cvf::Vec2ui(10, 320)); @@ -231,6 +233,7 @@ void RimReservoirView::updateViewerWidget() RiuMainWindow::instance()->addViewer(m_viewer); m_viewer->setMinNearPlaneDistance(10); this->cellResult()->legendConfig->recreateLegend(); + this->cellResult()->ternaryLegendConfig->recreateLegend(); this->cellEdgeResult()->legendConfig->recreateLegend(); m_viewer->setColorLegend1(this->cellResult()->legendConfig->legend()); m_viewer->setColorLegend2(this->cellEdgeResult()->legendConfig->legend()); @@ -529,7 +532,8 @@ void RimReservoirView::createDisplayModel() if (this->cellResult()->hasDynamicResult() || this->propertyFilterCollection()->hasActiveDynamicFilters() - || this->wellCollection->hasVisibleWellPipes()) + || this->wellCollection->hasVisibleWellPipes() + || this->cellResult()->isTernarySaturationSelected()) { CVF_ASSERT(currentGridCellResults()); @@ -648,10 +652,7 @@ void RimReservoirView::createDisplayModel() updateFaultForcedVisibility(); } - - this->updateFaultColors(); - // Compute triangle count, Debug only if (false) @@ -818,7 +819,7 @@ void RimReservoirView::updateCurrentTimeStep() { m_reservoirGridPartManager->updateCellEdgeResultColor(geometriesToRecolor[i], m_currentTimeStep, this->cellResult(), this->cellEdgeResult()); } - else if (this->animationMode() && this->cellResult()->hasResult()) + else if ((this->animationMode() && this->cellResult()->hasResult()) || this->cellResult()->isTernarySaturationSelected()) { m_reservoirGridPartManager->updateCellResultColor(geometriesToRecolor[i], m_currentTimeStep, this->cellResult()); } @@ -928,10 +929,16 @@ void RimReservoirView::loadDataAndUpdate() RiaApplication* app = RiaApplication::instance(); if (app->preferences()->autocomputeSOIL) { - RimReservoirCellResultsStorage* results = currentGridCellResults(); - CVF_ASSERT(results); - results->loadOrComputeSOIL(); - results->createCombinedTransmissibilityResults(); + { + RimReservoirCellResultsStorage* results = m_reservoir->results(RifReaderInterface::MATRIX_RESULTS); + results->loadOrComputeSOIL(); + results->createCombinedTransmissibilityResults(); + } + { + RimReservoirCellResultsStorage* results = m_reservoir->results(RifReaderInterface::FRACTURE_RESULTS); + results->loadOrComputeSOIL(); + results->createCombinedTransmissibilityResults(); + } } } } @@ -1107,7 +1114,38 @@ void RimReservoirView::appendCellResultInfo(size_t gridIndex, size_t cellIndex, RigCaseData* eclipseCase = m_reservoir->reservoirData(); RigGridBase* grid = eclipseCase->grid(gridIndex); - if (this->cellResult()->hasResult()) + RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResult()->porosityModel()); + cvf::ref dataAccessObject; + + if (this->cellResult()->isTernarySaturationSelected()) + { + RimReservoirCellResultsStorage* gridCellResults = this->cellResult()->currentGridCellResults(); + if (gridCellResults) + { + size_t soilScalarSetIndex = gridCellResults->findOrLoadScalarResult(RimDefines::DYNAMIC_NATIVE, "SOIL"); + size_t sgasScalarSetIndex = gridCellResults->findOrLoadScalarResult(RimDefines::DYNAMIC_NATIVE, "SGAS"); + size_t swatScalarSetIndex = gridCellResults->findOrLoadScalarResult(RimDefines::DYNAMIC_NATIVE, "SWAT"); + + cvf::ref dataAccessObjectX = eclipseCase->dataAccessObject(grid, porosityModel, m_currentTimeStep, soilScalarSetIndex); + cvf::ref dataAccessObjectY = eclipseCase->dataAccessObject(grid, porosityModel, m_currentTimeStep, sgasScalarSetIndex); + cvf::ref dataAccessObjectZ = eclipseCase->dataAccessObject(grid, porosityModel, m_currentTimeStep, swatScalarSetIndex); + + double scalarValue = 0.0; + + if (dataAccessObjectX.notNull()) scalarValue = dataAccessObjectX->cellScalar(cellIndex); + else scalarValue = 0.0; + resultInfoText->append(QString("SOIL : %1\n").arg(scalarValue)); + + if (dataAccessObjectY.notNull()) scalarValue = dataAccessObjectY->cellScalar(cellIndex); + else scalarValue = 0.0; + resultInfoText->append(QString("SGAS : %1\n").arg(scalarValue)); + + if (dataAccessObjectZ.notNull()) scalarValue = dataAccessObjectZ->cellScalar(cellIndex); + else scalarValue = 0.0; + resultInfoText->append(QString("SWAT : %1\n").arg(scalarValue)); + } + } + else if (this->cellResult()->hasResult()) { RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResult()->porosityModel()); cvf::ref dataAccessObject; @@ -1414,6 +1452,67 @@ void RimReservoirView::updateLegends() this->cellEdgeResult()->legendConfig->setClosestToZeroValues(0, 0, 0, 0); this->cellEdgeResult()->legendConfig->setAutomaticRanges(cvf::UNDEFINED_DOUBLE, cvf::UNDEFINED_DOUBLE, cvf::UNDEFINED_DOUBLE, cvf::UNDEFINED_DOUBLE); } + + + viewer()->removeOverlayItem(this->cellResult()->ternaryLegendConfig->legend()); + + size_t maxTimeStepCount = results->maxTimeStepCount(); + if (this->cellResult()->isTernarySaturationSelected() && maxTimeStepCount > 1) + { + RimReservoirCellResultsStorage* gridCellResults = this->cellResult()->currentGridCellResults(); + { + double globalMin = 0.0; + double globalMax = 1.0; + double localMin = 0.0; + double localMax = 1.0; + + size_t scalarSetIndex = gridCellResults->findOrLoadScalarResult(RimDefines::DYNAMIC_NATIVE, "SOIL"); + if (scalarSetIndex != cvf::UNDEFINED_SIZE_T) + { + results->minMaxCellScalarValues(scalarSetIndex, globalMin, globalMax); + results->minMaxCellScalarValues(scalarSetIndex, m_currentTimeStep, localMin, localMax); + + this->cellResult()->ternaryLegendConfig()->setAutomaticRanges(RimTernaryLegendConfig::TERNARY_SOIL_IDX, globalMin, globalMax, localMin, localMax); + } + } + + { + double globalMin = 0.0; + double globalMax = 1.0; + double localMin = 0.0; + double localMax = 1.0; + + size_t scalarSetIndex = gridCellResults->findOrLoadScalarResult(RimDefines::DYNAMIC_NATIVE, "SGAS"); + if (scalarSetIndex != cvf::UNDEFINED_SIZE_T) + { + results->minMaxCellScalarValues(scalarSetIndex, globalMin, globalMax); + results->minMaxCellScalarValues(scalarSetIndex, m_currentTimeStep, localMin, localMax); + + this->cellResult()->ternaryLegendConfig()->setAutomaticRanges(RimTernaryLegendConfig::TERNARY_SGAS_IDX, globalMin, globalMax, localMin, localMax); + } + } + + { + double globalMin = 0.0; + double globalMax = 1.0; + double localMin = 0.0; + double localMax = 1.0; + + size_t scalarSetIndex = gridCellResults->findOrLoadScalarResult(RimDefines::DYNAMIC_NATIVE, "SWAT"); + if (scalarSetIndex != cvf::UNDEFINED_SIZE_T) + { + results->minMaxCellScalarValues(scalarSetIndex, globalMin, globalMax); + results->minMaxCellScalarValues(scalarSetIndex, m_currentTimeStep, localMin, localMax); + + this->cellResult()->ternaryLegendConfig()->setAutomaticRanges(RimTernaryLegendConfig::TERNARY_SWAT_IDX, globalMin, globalMax, localMin, localMax); + } + } + + if (this->cellResult()->ternaryLegendConfig->legend()) + { + viewer()->addOverlayItem(this->cellResult()->ternaryLegendConfig->legend()); + } + } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimReservoirView.h b/ApplicationCode/ProjectDataModel/RimReservoirView.h index 6860e6dab0..a45a6c2e1d 100644 --- a/ApplicationCode/ProjectDataModel/RimReservoirView.h +++ b/ApplicationCode/ProjectDataModel/RimReservoirView.h @@ -57,6 +57,7 @@ namespace cvf class Transform; class ScalarMapperUniformLevels; class ModelBasicList; + class OverlayItem; } enum PartRenderMaskEnum diff --git a/ApplicationCode/ProjectDataModel/RimResultCase.cpp b/ApplicationCode/ProjectDataModel/RimResultCase.cpp index 4e9157ac22..d0d72587fa 100644 --- a/ApplicationCode/ProjectDataModel/RimResultCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimResultCase.cpp @@ -17,6 +17,13 @@ ///////////////////////////////////////////////////////////////////////////////// #include "RiaStdInclude.h" + +#include "cafProgressInfo.h" +#include "cafPdmSettings.h" +#include "cafPdmFieldCvfMat4d.h" +#include "cafPdmFieldCvfColor.h" +#include "cafPdmUiPropertyDialog.h" + #include "RimResultCase.h" #include "RigCaseData.h" #include "RifReaderEclipseOutput.h" @@ -24,7 +31,7 @@ #include "RimReservoirView.h" #include "RifReaderMockModel.h" #include "RifReaderEclipseInput.h" -#include "cafProgressInfo.h" + #include "RimProject.h" #include "RifEclipseOutputFileTools.h" #include "RiaApplication.h" @@ -34,8 +41,6 @@ #include "RimReservoirCellResultsCacher.h" #include "RimWellPathCollection.h" -#include "cafPdmFieldCvfMat4d.h" -#include "cafPdmFieldCvfColor.h" #include "RimResultSlot.h" #include "RimCellEdgeResultSlot.h" #include "RimCellRangeFilterCollection.h" @@ -45,6 +50,7 @@ #include "RimOilField.h" #include "RimAnalysisModels.h" #include "RiaPreferences.h" +#include "RimMockModelSettings.h" CAF_PDM_SOURCE_INIT(RimResultCase, "EclipseCase"); //-------------------------------------------------------------------------------------------------- @@ -199,29 +205,17 @@ cvf::ref RimResultCase::createMockModel(QString modelName) cvf::ref mockFileInterface = new RifReaderMockModel; cvf::ref reservoir = new RigCaseData; - if (modelName == "Result Mock Debug Model Simple") + if (modelName == RimDefines::mockModelBasic()) { // Create the mock file interface and and RigSerervoir and set them up. mockFileInterface->setWorldCoordinates(cvf::Vec3d(10, 10, 10), cvf::Vec3d(20, 20, 20)); mockFileInterface->setGridPointDimensions(cvf::Vec3st(4, 5, 6)); mockFileInterface->addLocalGridRefinement(cvf::Vec3st(0, 2, 2), cvf::Vec3st(0, 2, 2), cvf::Vec3st(3, 3, 3)); + mockFileInterface->enableWellData(false); mockFileInterface->open("", reservoir.p()); - { - size_t idx = reservoir->mainGrid()->cellIndexFromIJK(1, 3, 4); - - //TODO: Rewrite active cell info in mock models - //reservoir->mainGrid()->cell(idx).setActiveIndexInMatrixModel(cvf::UNDEFINED_SIZE_T); - } - - { - size_t idx = reservoir->mainGrid()->cellIndexFromIJK(2, 2, 3); - - //TODO: Rewrite active cell info in mock models - //reservoir->mainGrid()->cell(idx).setActiveIndexInMatrixModel(cvf::UNDEFINED_SIZE_T); - } } - else if (modelName == "Result Mock Debug Model With Results") + else if (modelName == RimDefines::mockModelBasicWithResults()) { mockFileInterface->setWorldCoordinates(cvf::Vec3d(10, 10, 10), cvf::Vec3d(-20, -20, -20)); mockFileInterface->setGridPointDimensions(cvf::Vec3st(5, 10, 20)); @@ -234,7 +228,7 @@ cvf::ref RimResultCase::createMockModel(QString modelName) cvf::Vec3d& tmp = reservoir->mainGrid()->nodes()[1]; tmp += cvf::Vec3d(1, 0, 0); } - else if (modelName =="Result Mock Debug Model Large With Results") + else if (modelName == RimDefines::mockModelLargeWithResults()) { double startX = 0; double startY = 0; @@ -262,6 +256,45 @@ cvf::ref RimResultCase::createMockModel(QString modelName) mockFileInterface->open("", reservoir.p()); } + else if (modelName == RimDefines::mockModelCustomized()) + { + QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); + + RimMockModelSettings rimMockModelSettings; + caf::Settings::readFieldsFromApplicationStore(&rimMockModelSettings); + + caf::PdmUiPropertyDialog propertyDialog(NULL, &rimMockModelSettings, "Customize Mock Model"); + if (propertyDialog.exec() == QDialog::Accepted) + { + QApplication::restoreOverrideCursor(); + + caf::Settings::writeFieldsToApplicationStore(&rimMockModelSettings); + + double startX = 0; + double startY = 0; + double startZ = 0; + + double widthX = 6000; + double widthY = 12000; + double widthZ = 500; + + // Test code to simulate UTM coordinates + double offsetX = 400000; + double offsetY = 6000000; + double offsetZ = 0; + + mockFileInterface->setWorldCoordinates(cvf::Vec3d(startX + offsetX, startY + offsetY, startZ + offsetZ), cvf::Vec3d(startX + widthX + offsetX, startY + widthY + offsetY, startZ + widthZ + offsetZ)); + mockFileInterface->setGridPointDimensions(cvf::Vec3st(rimMockModelSettings.cellCountX + 1, rimMockModelSettings.cellCountY + 1, rimMockModelSettings.cellCountZ + 1)); + mockFileInterface->setResultInfo(rimMockModelSettings.resultCount, rimMockModelSettings.timeStepCount); + mockFileInterface->enableWellData(false); + + mockFileInterface->open("", reservoir.p()); + } + else + { + QApplication::restoreOverrideCursor(); + } + } this->setReservoirData( reservoir.p() ); diff --git a/ApplicationCode/ProjectDataModel/RimResultDefinition.cpp b/ApplicationCode/ProjectDataModel/RimResultDefinition.cpp index ed298330b8..110036ffb8 100644 --- a/ApplicationCode/ProjectDataModel/RimResultDefinition.cpp +++ b/ApplicationCode/ProjectDataModel/RimResultDefinition.cpp @@ -160,10 +160,10 @@ QList RimResultDefinition::calculateValueOptions(const c QStringList varList = getResultVariableListForCurrentUIFieldSettings(); bool hasCombinedTransmissibility = false; + QList optionList; for (int i = 0; i < varList.size(); ++i) { - if (varList[i].compare(RimDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0) { hasCombinedTransmissibility = true; @@ -171,7 +171,6 @@ QList RimResultDefinition::calculateValueOptions(const c } optionList.push_back(caf::PdmOptionItemInfo(varList[i], varList[i])); - } if (hasCombinedTransmissibility) @@ -179,6 +178,16 @@ QList RimResultDefinition::calculateValueOptions(const c optionList.push_front(caf::PdmOptionItemInfo(RimDefines::combinedTransmissibilityResultName(), RimDefines::combinedTransmissibilityResultName())); } + bool hasAtLeastOneTernaryComponent = false; + if (varList.contains("SOIL")) hasAtLeastOneTernaryComponent = true; + else if (varList.contains("SGAS")) hasAtLeastOneTernaryComponent = true; + else if (varList.contains("SWAT")) hasAtLeastOneTernaryComponent = true; + + if (m_resultTypeUiField == RimDefines::DYNAMIC_NATIVE && hasAtLeastOneTernaryComponent) + { + optionList.push_front(caf::PdmOptionItemInfo(RimDefines::ternarySaturationResultName(), RimDefines::ternarySaturationResultName())); + } + optionList.push_front(caf::PdmOptionItemInfo( RimDefines::undefinedResultName(), RimDefines::undefinedResultName() )); if (useOptionsOnly) *useOptionsOnly = true; @@ -223,7 +232,6 @@ void RimResultDefinition::loadResult() gridCellResults->findOrLoadScalarResult(m_resultType(), m_resultVariable); } } - } @@ -251,7 +259,6 @@ bool RimResultDefinition::hasStaticResult() const //-------------------------------------------------------------------------------------------------- bool RimResultDefinition::hasResult() const { - if (this->currentGridCellResults() && this->currentGridCellResults()->cellResults()) { const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults()->cellResults(); @@ -341,3 +348,14 @@ void RimResultDefinition::setPorosityModelUiFieldHidden(bool hide) { m_porosityModelUiField.setUiHidden(true); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimResultDefinition::isTernarySaturationSelected() const +{ + bool isTernary = (m_resultType() == RimDefines::DYNAMIC_NATIVE) && + (m_resultVariable().compare(RimDefines::ternarySaturationResultName(), Qt::CaseInsensitive) == 0); + + return isTernary; +} diff --git a/ApplicationCode/ProjectDataModel/RimResultDefinition.h b/ApplicationCode/ProjectDataModel/RimResultDefinition.h index 2c7b6c28cf..3e7e463f7d 100644 --- a/ApplicationCode/ProjectDataModel/RimResultDefinition.h +++ b/ApplicationCode/ProjectDataModel/RimResultDefinition.h @@ -47,7 +47,7 @@ class RimResultDefinition : public caf::PdmObject RimDefines::PorosityModelType porosityModel() const { return m_porosityModel(); } void setPorosityModel(RimDefines::PorosityModelType val); QString resultVariable() const { return m_resultVariable(); } - void setResultVariable(const QString& val); + virtual void setResultVariable(const QString& val); void setPorosityModelUiFieldHidden(bool hide); void loadResult(); @@ -55,6 +55,8 @@ class RimResultDefinition : public caf::PdmObject bool hasStaticResult() const; bool hasDynamicResult() const; bool hasResult() const; + bool isTernarySaturationSelected() const; + RimReservoirCellResultsStorage* currentGridCellResults() const; diff --git a/ApplicationCode/ProjectDataModel/RimResultSlot.cpp b/ApplicationCode/ProjectDataModel/RimResultSlot.cpp index e7bdec4640..38108eaf5f 100644 --- a/ApplicationCode/ProjectDataModel/RimResultSlot.cpp +++ b/ApplicationCode/ProjectDataModel/RimResultSlot.cpp @@ -19,23 +19,11 @@ #include "RiaStdInclude.h" #include "RimResultSlot.h" -#include "RimLegendConfig.h" + #include "RimReservoirView.h" -#include "RimCase.h" -#include "RiuMainWindow.h" +#include "RimTernaryLegendConfig.h" #include "RimUiTreeModelPdm.h" - - -#include "cafPdmFieldCvfMat4d.h" -#include "cafPdmFieldCvfColor.h" -#include "RimResultSlot.h" -#include "RimCellEdgeResultSlot.h" -#include "RimCellRangeFilterCollection.h" -#include "RimCellPropertyFilterCollection.h" -#include "RimWellCollection.h" -#include "Rim3dOverlayInfoConfig.h" - -#include "RimReservoirCellResultsCacher.h" +#include "RiuMainWindow.h" CAF_PDM_SOURCE_INIT(RimResultSlot, "ResultSlot"); @@ -47,11 +35,18 @@ RimResultSlot::RimResultSlot() CAF_PDM_InitObject("Result Slot", "", "", ""); CAF_PDM_InitFieldNoDefault(&legendConfig, "LegendDefinition", "Legend Definition", "", "", ""); + this->legendConfig = new RimLegendConfig(); + this->legendConfig.setUiHidden(true); + this->legendConfig.setUiChildrenHidden(true); + CAF_PDM_InitFieldNoDefault(&m_legendConfigData, "ResultVarLegendDefinitionList", "", "", "", ""); m_legendConfigData.setUiHidden(true); m_legendConfigData.setUiChildrenHidden(true); - legendConfig = new RimLegendConfig(); + CAF_PDM_InitFieldNoDefault(&ternaryLegendConfig, "TernaryLegendDefinition", "Ternary Legend Definition", "", "", ""); + this->ternaryLegendConfig = new RimTernaryLegendConfig(); + this->ternaryLegendConfig.setUiHidden(true); + this->ternaryLegendConfig.setUiChildrenHidden(true); } //-------------------------------------------------------------------------------------------------- @@ -60,6 +55,7 @@ RimResultSlot::RimResultSlot() RimResultSlot::~RimResultSlot() { delete legendConfig(); + delete ternaryLegendConfig(); } //-------------------------------------------------------------------------------------------------- @@ -81,6 +77,8 @@ void RimResultSlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, co { if (m_reservoirView) m_reservoirView->animationMode = true; } + + RiuMainWindow::instance()->uiPdmModel()->updateUiSubTree(this); } if (m_reservoirView) m_reservoirView->createDisplayModelAndRedraw(); @@ -91,36 +89,51 @@ void RimResultSlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, co //-------------------------------------------------------------------------------------------------- void RimResultSlot::changeLegendConfig(QString resultVarNameOfNewLegend) { - if (this->legendConfig()->resultVariableName() == resultVarNameOfNewLegend) return; - - std::list >::iterator it; - bool found = false; - for (it = m_legendConfigData.v().begin(); it != m_legendConfigData.v().end(); ++it) + if (resultVarNameOfNewLegend == RimDefines::ternarySaturationResultName()) + { + this->ternaryLegendConfig.setUiHidden(false); + this->ternaryLegendConfig.setUiChildrenHidden(false); + this->legendConfig.setUiHidden(true); + this->legendConfig.setUiChildrenHidden(true); + } + else { - if ((*it)->resultVariableName() == resultVarNameOfNewLegend) + this->ternaryLegendConfig.setUiHidden(true); + this->ternaryLegendConfig.setUiChildrenHidden(true); + + if (this->legendConfig()->resultVariableName() != resultVarNameOfNewLegend) { - RimLegendConfig* newLegend = *it; + std::list >::iterator it; + bool found = false; + for (it = m_legendConfigData.v().begin(); it != m_legendConfigData.v().end(); ++it) + { + if ((*it)->resultVariableName() == resultVarNameOfNewLegend) + { + RimLegendConfig* newLegend = *it; - m_legendConfigData.v().erase(it); - m_legendConfigData.v().push_back(this->legendConfig()); - this->legendConfig = newLegend; - RiuMainWindow::instance()->uiPdmModel()->updateUiSubTree(this); - found = true; - break; + m_legendConfigData.v().erase(it); + m_legendConfigData.v().push_back(this->legendConfig()); + this->legendConfig = newLegend; + found = true; + break; + } + } + + // Not found ? + if (!found) + { + RimLegendConfig* newLegend = new RimLegendConfig; + newLegend->setReservoirView(m_reservoirView); + newLegend->resultVariableName = resultVarNameOfNewLegend; + m_legendConfigData.v().push_back(this->legendConfig()); + this->legendConfig = newLegend; + } } + + this->legendConfig.setUiHidden(false); + this->legendConfig.setUiChildrenHidden(false); } - // Not found ? - if (!found) - { - RimLegendConfig* newLegend = new RimLegendConfig; - newLegend->setReservoirView(m_reservoirView); - newLegend->resultVariableName = resultVarNameOfNewLegend; - m_legendConfigData.v().push_back(this->legendConfig()); - this->legendConfig = newLegend; - RiuMainWindow::instance()->uiPdmModel()->updateUiSubTree(this); - - } } //-------------------------------------------------------------------------------------------------- @@ -134,6 +147,8 @@ void RimResultSlot::initAfterRead() { this->legendConfig()->resultVariableName = this->resultVariable(); } + + changeLegendConfig(this->resultVariable()); } //-------------------------------------------------------------------------------------------------- @@ -148,4 +163,17 @@ void RimResultSlot::setReservoirView(RimReservoirView* ownerReservoirView) { (*it)->setReservoirView(ownerReservoirView); } + + this->ternaryLegendConfig()->setReservoirView(ownerReservoirView); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimResultSlot::setResultVariable(const QString& val) +{ + RimResultDefinition::setResultVariable(val); + + this->changeLegendConfig(val); } + diff --git a/ApplicationCode/ProjectDataModel/RimResultSlot.h b/ApplicationCode/ProjectDataModel/RimResultSlot.h index 29c91a68f2..afa92bb3a3 100644 --- a/ApplicationCode/ProjectDataModel/RimResultSlot.h +++ b/ApplicationCode/ProjectDataModel/RimResultSlot.h @@ -18,12 +18,15 @@ #pragma once -#include "cafPdmObject.h" -#include "RimLegendConfig.h" #include "cafAppEnum.h" +#include "cafPdmObject.h" + #include "RimDefines.h" +#include "RimLegendConfig.h" #include "RimResultDefinition.h" +class RimTernaryLegendConfig; + //================================================================================================== /// /// @@ -37,16 +40,18 @@ class RimResultSlot : public RimResultDefinition virtual void setReservoirView(RimReservoirView* ownerReservoirView); caf::PdmField legendConfig; + caf::PdmField ternaryLegendConfig; // Overridden methods - virtual void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ); + virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); + virtual void setResultVariable(const QString& resultName); + protected: virtual void initAfterRead(); private: void changeLegendConfig(QString resultVarNameOfNewLegend); - caf::PdmField > > m_legendConfigData; - + caf::PdmField > > m_legendConfigData; }; diff --git a/ApplicationCode/ProjectDataModel/RimTernaryLegendConfig.cpp b/ApplicationCode/ProjectDataModel/RimTernaryLegendConfig.cpp new file mode 100644 index 0000000000..4f5a9bcde6 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimTernaryLegendConfig.cpp @@ -0,0 +1,440 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimTernaryLegendConfig.h" + +#include "cafPdmUiPushButtonEditor.h" +#include "cafPdmUiTextEditor.h" + +#include "RiaApplication.h" +#include "RimReservoirView.h" + +#include "RivTernarySaturationOverlayItem.h" + +#include +#include "cvfqtUtils.h" + + +CAF_PDM_SOURCE_INIT(RimTernaryLegendConfig, "RimTernaryLegendConfig"); + +namespace caf { + template<> + void AppEnum::setUp() + { + addItem(RimTernaryLegendConfig::AUTOMATIC_ALLTIMESTEPS, "AUTOMATIC_ALLTIMESTEPS", "Global range"); + addItem(RimTernaryLegendConfig::AUTOMATIC_CURRENT_TIMESTEP,"AUTOMATIC_CURRENT_TIMESTEP", "Local range"); + addItem(RimTernaryLegendConfig::USER_DEFINED, "USER_DEFINED_MAX_MIN", "User defined range"); + setDefault(RimTernaryLegendConfig::AUTOMATIC_ALLTIMESTEPS); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimTernaryLegendConfig::RimTernaryLegendConfig() +{ + CAF_PDM_InitObject("Ternary Legend Definition", ":/Legend.png", "", ""); + + CAF_PDM_InitField(&precision, "Precision", 2, "Significant digits", "", "The number of significant digits displayed in the legend numbers",""); + CAF_PDM_InitField(&rangeMode, "RangeType", RangeModeEnum(USER_DEFINED), "Range type", "", "Switches between automatic and user defined range on the legend", ""); + + CAF_PDM_InitFieldNoDefault(&applyLocalMinMax, "m_applyLocalMinMax", "", "", "", ""); + applyLocalMinMax.setIOWritable(false); + applyLocalMinMax.setIOReadable(false); + applyLocalMinMax.setUiEditorTypeName(caf::PdmUiPushButtonEditor::uiEditorTypeName()); + applyLocalMinMax.setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + applyLocalMinMax = false; + + CAF_PDM_InitFieldNoDefault(&applyGlobalMinMax, "m_applyGlobalMinMax", "", "", "", ""); + applyGlobalMinMax.setIOWritable(false); + applyGlobalMinMax.setIOReadable(false); + applyGlobalMinMax.setUiEditorTypeName(caf::PdmUiPushButtonEditor::uiEditorTypeName()); + applyGlobalMinMax.setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + applyGlobalMinMax = false; + + CAF_PDM_InitFieldNoDefault(&applyFullRangeMinMax, "m_applyFullRangeMinMax", "", "", "", ""); + applyFullRangeMinMax.setIOWritable(false); + applyFullRangeMinMax.setIOReadable(false); + applyFullRangeMinMax.setUiEditorTypeName(caf::PdmUiPushButtonEditor::uiEditorTypeName()); + applyFullRangeMinMax.setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + applyFullRangeMinMax = false; + + CAF_PDM_InitFieldNoDefault(&ternaryRangeSummary, "ternaryRangeSummary", "Range summary", "", "", ""); + ternaryRangeSummary.setUiEditorTypeName(caf::PdmUiTextEditor::uiEditorTypeName()); + ternaryRangeSummary.setUiLabelPosition(caf::PdmUiItemInfo::TOP); + + + CAF_PDM_InitField(&userDefinedMaxValueSoil, "UserDefinedMaxSoil", 1.0, "Max", "", "Min value of the legend", ""); + CAF_PDM_InitField(&userDefinedMinValueSoil, "UserDefinedMinSoil", 0.0, "Min", "", "Max value of the legend", ""); + + CAF_PDM_InitField(&userDefinedMaxValueSgas, "UserDefinedMaxSgas", 1.0, "Max", "", "Min value of the legend", ""); + CAF_PDM_InitField(&userDefinedMinValueSgas, "UserDefinedMinSgas", 0.0, "Min", "", "Max value of the legend", ""); + + CAF_PDM_InitField(&userDefinedMaxValueSwat, "UserDefinedMaxSwat", 1.0, "Max", "", "Min value of the legend", ""); + CAF_PDM_InitField(&userDefinedMinValueSwat, "UserDefinedMinSwat", 0.0, "Min", "", "Max value of the legend", ""); + + m_globalAutoMin.resize(3, 0.0); + m_globalAutoMax.resize(3, 1.0); + m_localAutoMin.resize(3, 0.0); + m_localAutoMax.resize(3, 1.0); + + recreateLegend(); + updateLegend(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimTernaryLegendConfig::~RimTernaryLegendConfig() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTernaryLegendConfig::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +{ + if (changedField == &applyLocalMinMax) + { + userDefinedMaxValueSoil = m_localAutoMax[TERNARY_SOIL_IDX]; + userDefinedMinValueSoil = m_localAutoMin[TERNARY_SOIL_IDX]; + userDefinedMaxValueSgas = m_localAutoMax[TERNARY_SGAS_IDX]; + userDefinedMinValueSgas = m_localAutoMin[TERNARY_SGAS_IDX]; + userDefinedMaxValueSwat = m_localAutoMax[TERNARY_SWAT_IDX]; + userDefinedMinValueSwat = m_localAutoMin[TERNARY_SWAT_IDX]; + + applyLocalMinMax = false; + } + else if (changedField == &applyGlobalMinMax) + { + userDefinedMaxValueSoil = m_globalAutoMax[TERNARY_SOIL_IDX]; + userDefinedMinValueSoil = m_globalAutoMin[TERNARY_SOIL_IDX]; + userDefinedMaxValueSgas = m_globalAutoMax[TERNARY_SGAS_IDX]; + userDefinedMinValueSgas = m_globalAutoMin[TERNARY_SGAS_IDX]; + userDefinedMaxValueSwat = m_globalAutoMax[TERNARY_SWAT_IDX]; + userDefinedMinValueSwat = m_globalAutoMin[TERNARY_SWAT_IDX]; + + applyGlobalMinMax = false; + } + else if (changedField == &applyFullRangeMinMax) + { + userDefinedMaxValueSoil = 1.0; + userDefinedMinValueSoil = 0.0; + userDefinedMaxValueSgas = 1.0; + userDefinedMinValueSgas = 0.0; + userDefinedMaxValueSwat = 1.0; + userDefinedMinValueSwat = 0.0; + + applyFullRangeMinMax = false; + } + + updateLabelText(); + updateLegend(); + + if (m_reservoirView) m_reservoirView->updateCurrentTimeStepAndRedraw(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTernaryLegendConfig::updateLegend() +{ + double soilLower = 0.0; + double soilUpper = 1.0; + double sgasLower = 0.0; + double sgasUpper = 1.0; + double swatLower = 0.0; + double swatUpper = 1.0; + + ternaryRanges(soilLower, soilUpper, sgasLower, sgasUpper, swatLower, swatUpper); + + cvf::String soilRange; + cvf::String sgasRange; + cvf::String swatRange; + + int numberPrecision = 1; + { + QString tmpString = QString::number(soilLower, 'g', numberPrecision) + " - " + QString::number(soilUpper, 'g', numberPrecision); + soilRange = cvfqt::Utils::toString(tmpString); + } + + { + QString tmpString = QString::number(sgasLower, 'g', numberPrecision) + " - " + QString::number(sgasUpper, 'g', numberPrecision); + sgasRange = cvfqt::Utils::toString(tmpString); + } + + { + QString tmpString = QString::number(swatLower, 'g', numberPrecision) + " - " + QString::number(swatUpper, 'g', numberPrecision); + swatRange = cvfqt::Utils::toString(tmpString); + } + + if (!m_legend.isNull()) + { + m_legend->setRangeText(soilRange, sgasRange, swatRange); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTernaryLegendConfig::setAutomaticRanges(TernaryArrayIndex ternaryIndex, double globalMin, double globalMax, double localMin, double localMax) +{ + double candidateGlobalAutoMin = roundToNumSignificantDigits(globalMin, precision); + double candidateGlobalAutoMax = roundToNumSignificantDigits(globalMax, precision); + + double candidateLocalAutoMin = roundToNumSignificantDigits(localMin, precision); + double candidateLocalAutoMax = roundToNumSignificantDigits(localMax, precision); + + m_globalAutoMin[ternaryIndex] = candidateGlobalAutoMin; + m_globalAutoMax[ternaryIndex] = candidateGlobalAutoMax; + m_localAutoMin[ternaryIndex] = candidateLocalAutoMin; + m_localAutoMax[ternaryIndex] = candidateLocalAutoMax; + + updateLabelText(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTernaryLegendConfig::recreateLegend() +{ + // Due to possible visualization bug, we need to recreate the legend if the last viewer + // has been removed, (and thus the opengl resources has been deleted) The text in + // the legend disappeared because of this, so workaround: recreate the legend when needed: + + cvf::Font* standardFont = RiaApplication::instance()->standardFont(); + m_legend = new RivTernarySaturationOverlayItem(standardFont); + m_legend->setLayout(cvf::OverlayItem::VERTICAL, cvf::OverlayItem::BOTTOM_LEFT); + + updateLegend(); +} + +//-------------------------------------------------------------------------------------------------- +/// Rounding the double value to given number of significant digits +//-------------------------------------------------------------------------------------------------- +double RimTernaryLegendConfig::roundToNumSignificantDigits(double domainValue, double numSignificantDigits) +{ + double absDomainValue = cvf::Math::abs(domainValue); + if (absDomainValue == 0.0) + { + return 0.0; + } + + double logDecValue = log10(absDomainValue); + logDecValue = cvf::Math::ceil(logDecValue); + + double factor = pow(10.0, numSignificantDigits - logDecValue); + + double tmp = domainValue * factor; + double integerPart; + double fraction = modf(tmp, &integerPart); + + if (cvf::Math::abs(fraction)>= 0.5) (integerPart >= 0) ? integerPart++: integerPart-- ; + + double newDomainValue = integerPart / factor; + + return newDomainValue; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTernaryLegendConfig::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + caf::PdmUiOrdering* formatGr = uiOrdering.addNewGroup("Format"); + formatGr->add(&precision); + formatGr->add(&rangeMode); + + if (rangeMode == USER_DEFINED) + { + caf::PdmUiOrdering* ternaryGroupContainer = uiOrdering.addNewGroup("Ternary "); + { + caf::PdmUiOrdering* ternaryGroup = ternaryGroupContainer->addNewGroup("SOIL"); + ternaryGroup->add(&userDefinedMinValueSoil); + ternaryGroup->add(&userDefinedMaxValueSoil); + } + + { + caf::PdmUiOrdering* ternaryGroup = ternaryGroupContainer->addNewGroup("SGAS"); + ternaryGroup->add(&userDefinedMinValueSgas); + ternaryGroup->add(&userDefinedMaxValueSgas); + } + + { + caf::PdmUiOrdering* ternaryGroup = ternaryGroupContainer->addNewGroup("SWAT"); + ternaryGroup->add(&userDefinedMinValueSwat); + ternaryGroup->add(&userDefinedMaxValueSwat); + } + + ternaryGroupContainer->add(&applyLocalMinMax); + ternaryGroupContainer->add(&applyGlobalMinMax); + ternaryGroupContainer->add(&applyFullRangeMinMax); + } + else + { + caf::PdmUiOrdering* group = uiOrdering.addNewGroup("Summary"); + group->add(&ternaryRangeSummary); + } + + uiOrdering.setForgetRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::OverlayItem* RimTernaryLegendConfig::legend() +{ + return m_legend.p(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTernaryLegendConfig::defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) +{ + if (&applyLocalMinMax == field) + { + caf::PdmUiPushButtonEditorAttribute* attrib = dynamic_cast (attribute); + if (attrib) + { + attrib->m_buttonText = "Apply local min/max values"; + } + } + else if (&applyGlobalMinMax == field) + { + caf::PdmUiPushButtonEditorAttribute* attrib = dynamic_cast (attribute); + if (attrib) + { + attrib->m_buttonText = "Apply global min/max values"; + } + } + else if (&applyFullRangeMinMax == field) + { + caf::PdmUiPushButtonEditorAttribute* attrib = dynamic_cast (attribute); + if (attrib) + { + attrib->m_buttonText = "Apply full range"; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTernaryLegendConfig::ternaryRanges(double& soilLower, double& soilUpper, double& sgasLower, double& sgasUpper, double& swatLower, double& swatUpper) const +{ + if (rangeMode() == AUTOMATIC_CURRENT_TIMESTEP) + { + soilLower = m_localAutoMin[TERNARY_SOIL_IDX]; + soilUpper = m_localAutoMax[TERNARY_SOIL_IDX]; + sgasLower = m_localAutoMin[TERNARY_SGAS_IDX]; + sgasUpper = m_localAutoMax[TERNARY_SGAS_IDX]; + swatLower = m_localAutoMin[TERNARY_SWAT_IDX]; + swatUpper = m_localAutoMax[TERNARY_SWAT_IDX]; + } + else if (rangeMode() == AUTOMATIC_ALLTIMESTEPS) + { + soilLower = m_globalAutoMin[TERNARY_SOIL_IDX]; + soilUpper = m_globalAutoMax[TERNARY_SOIL_IDX]; + sgasLower = m_globalAutoMin[TERNARY_SGAS_IDX]; + sgasUpper = m_globalAutoMax[TERNARY_SGAS_IDX]; + swatLower = m_globalAutoMin[TERNARY_SWAT_IDX]; + swatUpper = m_globalAutoMax[TERNARY_SWAT_IDX]; + } + else + { + soilLower = userDefinedMinValueSoil; + soilUpper = userDefinedMaxValueSoil; + sgasLower = userDefinedMinValueSgas; + sgasUpper = userDefinedMaxValueSgas; + swatLower = userDefinedMinValueSwat; + swatUpper = userDefinedMaxValueSwat; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTernaryLegendConfig::updateLabelText() +{ + { + userDefinedMinValueSoil.setUiName("Min"); + userDefinedMaxValueSoil.setUiName("Max"); + + if (m_globalAutoMin[TERNARY_SOIL_IDX] != cvf::UNDEFINED_DOUBLE ) + { + userDefinedMinValueSoil.setUiName(QString("Min ") + "(" + QString::number(m_globalAutoMin[TERNARY_SOIL_IDX], 'g', precision) + ")"); + } + + if (m_globalAutoMax[TERNARY_SOIL_IDX] != cvf::UNDEFINED_DOUBLE ) + { + userDefinedMaxValueSoil.setUiName(QString("Max ") + "(" + QString::number(m_globalAutoMax[TERNARY_SOIL_IDX], 'g', precision) + ")"); + } + } + + { + userDefinedMinValueSgas.setUiName("Min"); + userDefinedMaxValueSgas.setUiName("Max"); + + if (m_globalAutoMin[TERNARY_SGAS_IDX] != cvf::UNDEFINED_DOUBLE ) + { + userDefinedMinValueSgas.setUiName(QString("Min ") + "(" + QString::number(m_globalAutoMin[TERNARY_SGAS_IDX], 'g', precision) + ")"); + } + + if (m_globalAutoMax[TERNARY_SGAS_IDX] != cvf::UNDEFINED_DOUBLE ) + { + userDefinedMaxValueSgas.setUiName(QString("Max ") + "(" + QString::number(m_globalAutoMax[TERNARY_SGAS_IDX], 'g', precision) + ")"); + } + } + + { + userDefinedMinValueSwat.setUiName("Min"); + userDefinedMaxValueSwat.setUiName("Max"); + + if (m_globalAutoMin[TERNARY_SWAT_IDX] != cvf::UNDEFINED_DOUBLE ) + { + userDefinedMinValueSwat.setUiName(QString("Min ") + "(" + QString::number(m_globalAutoMin[TERNARY_SWAT_IDX], 'g', precision) + ")"); + } + + if (m_globalAutoMax[TERNARY_SWAT_IDX] != cvf::UNDEFINED_DOUBLE ) + { + userDefinedMaxValueSwat.setUiName(QString("Max ") + "(" + QString::number(m_globalAutoMax[TERNARY_SWAT_IDX], 'g', precision) + ")"); + } + } + + if (rangeMode == AUTOMATIC_ALLTIMESTEPS) + { + QString tmpString; + tmpString = QString("SOIL : ") + QString::number(m_globalAutoMin[TERNARY_SOIL_IDX], 'g', precision) + " - " + QString::number(m_globalAutoMax[TERNARY_SOIL_IDX], 'g', precision) + "\n"; + tmpString += QString("SGAS : ") + QString::number(m_globalAutoMin[TERNARY_SGAS_IDX], 'g', precision) + " - " + QString::number(m_globalAutoMax[TERNARY_SGAS_IDX], 'g', precision) + "\n"; + tmpString += QString("SWAT : ") + QString::number(m_globalAutoMin[TERNARY_SWAT_IDX], 'g', precision) + " - " + QString::number(m_globalAutoMax[TERNARY_SWAT_IDX], 'g', precision) + "\n"; + + ternaryRangeSummary = tmpString; + } + else if (rangeMode == AUTOMATIC_CURRENT_TIMESTEP) + { + QString tmpString; + tmpString = QString("SOIL : ") + QString::number(m_localAutoMin[TERNARY_SOIL_IDX], 'g', precision) + " - " + QString::number(m_localAutoMax[TERNARY_SOIL_IDX], 'g', precision) + "\n"; + tmpString += QString("SGAS : ") + QString::number(m_localAutoMin[TERNARY_SGAS_IDX], 'g', precision) + " - " + QString::number(m_localAutoMax[TERNARY_SGAS_IDX], 'g', precision) + "\n"; + tmpString += QString("SWAT : ") + QString::number(m_localAutoMin[TERNARY_SWAT_IDX], 'g', precision) + " - " + QString::number(m_localAutoMax[TERNARY_SWAT_IDX], 'g', precision) + "\n"; + + ternaryRangeSummary = tmpString; + } +} + diff --git a/ApplicationCode/ProjectDataModel/RimTernaryLegendConfig.h b/ApplicationCode/ProjectDataModel/RimTernaryLegendConfig.h new file mode 100644 index 0000000000..6697441da9 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimTernaryLegendConfig.h @@ -0,0 +1,108 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfObject.h" + +#include "cafAppEnum.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +class RimReservoirView; +class RivTernarySaturationOverlayItem; + +namespace cvf +{ + class OverlayItem; +} + + + +//================================================================================================== +/// +/// +//================================================================================================== +class RimTernaryLegendConfig : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + enum TernaryArrayIndex + { + TERNARY_SOIL_IDX = 0, + TERNARY_SGAS_IDX, + TERNARY_SWAT_IDX + }; + + enum RangeModeType + { + AUTOMATIC_ALLTIMESTEPS, + AUTOMATIC_CURRENT_TIMESTEP, + USER_DEFINED + }; + typedef caf::AppEnum RangeModeEnum; + +public: + RimTernaryLegendConfig(); + virtual ~RimTernaryLegendConfig(); + + void setReservoirView(RimReservoirView* ownerReservoirView) {m_reservoirView = ownerReservoirView; } + + void setAutomaticRanges(TernaryArrayIndex ternaryIndex, double globalMin, double globalMax, double localMin, double localMax); + void ternaryRanges(double& soilLower, double& soilUpper, double& sgasLower, double& sgasUpper, double& swatLower, double& swatUpper) const; + + void recreateLegend(); + cvf::OverlayItem* legend(); + +protected: + virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); + virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering ); + virtual void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute); + +private: + void updateLegend(); + void updateLabelText(); + double roundToNumSignificantDigits(double value, double precision); + + +private: + caf::PdmField precision; + caf::PdmField rangeMode; + + caf::PdmField userDefinedMaxValueSoil; + caf::PdmField userDefinedMinValueSoil; + caf::PdmField userDefinedMaxValueSgas; + caf::PdmField userDefinedMinValueSgas; + caf::PdmField userDefinedMaxValueSwat; + caf::PdmField userDefinedMinValueSwat; + + caf::PdmField applyLocalMinMax; + caf::PdmField applyGlobalMinMax; + caf::PdmField applyFullRangeMinMax; + caf::PdmField ternaryRangeSummary; + + std::vector m_globalAutoMax; + std::vector m_globalAutoMin; + std::vector m_localAutoMax; + std::vector m_localAutoMin; + + caf::PdmPointer m_reservoirView; + cvf::ref m_legend; +}; diff --git a/ApplicationCode/ProjectDataModel/RimUiTreeView.cpp b/ApplicationCode/ProjectDataModel/RimUiTreeView.cpp index 272c7cca9b..690c0bdfa7 100644 --- a/ApplicationCode/ProjectDataModel/RimUiTreeView.cpp +++ b/ApplicationCode/ProjectDataModel/RimUiTreeView.cpp @@ -19,6 +19,9 @@ //#include "RiaStdInclude.h" #include "cafPdmDocument.h" +#include "cafPdmFieldCvfColor.h" +#include "cafPdmFieldCvfMat4d.h" +#include "cafPdmUiPropertyDialog.h" #include #include @@ -37,7 +40,6 @@ #include "RimInputPropertyCollection.h" #include "RimExportInputPropertySettings.h" #include "RiaPreferences.h" -#include "RiuPreferencesDialog.h" #include "RifEclipseInputFileTools.h" #include "RimInputCase.h" #include "RimBinaryExportSettings.h" @@ -59,9 +61,6 @@ #include "RimWellPathCollection.h" #include "RimReservoirCellResultsCacher.h" #include "Rim3dOverlayInfoConfig.h" - -#include "cafPdmFieldCvfColor.h" -#include "cafPdmFieldCvfMat4d.h" #include "RimProject.h" #include "RimOilField.h" #include "RimAnalysisModels.h" @@ -834,8 +833,8 @@ void RimUiTreeView::slotWriteInputProperty() exportSettings.fileName = outputFileName; } - RiuPreferencesDialog preferencesDialog(this, &exportSettings, "Export Eclipse Property to Text File"); - if (preferencesDialog.exec() == QDialog::Accepted) + caf::PdmUiPropertyDialog propertyDialog(this, &exportSettings, "Export Eclipse Property to Text File"); + if (propertyDialog.exec() == QDialog::Accepted) { bool isOk = RifEclipseInputFileTools::writePropertyToTextFile(exportSettings.fileName, inputReservoir->reservoirData(), 0, inputProperty->resultName, exportSettings.eclipseKeyword); if (isOk) @@ -887,8 +886,8 @@ void RimUiTreeView::slotWriteBinaryResultAsInputProperty() exportSettings.fileName = outputFileName; } - RiuPreferencesDialog preferencesDialog(this, &exportSettings, "Export Binary Eclipse Data to Text File"); - if (preferencesDialog.exec() == QDialog::Accepted) + caf::PdmUiPropertyDialog propertyDialog(this, &exportSettings, "Export Binary Eclipse Data to Text File"); + if (propertyDialog.exec() == QDialog::Accepted) { size_t timeStep = resultSlot->reservoirView()->currentTimeStep(); RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(resultSlot->porosityModel()); diff --git a/ApplicationCode/ReservoirDataModel/RigActiveCellInfo.cpp b/ApplicationCode/ReservoirDataModel/RigActiveCellInfo.cpp index bb0da770da..b58b17c5d4 100644 --- a/ApplicationCode/ReservoirDataModel/RigActiveCellInfo.cpp +++ b/ApplicationCode/ReservoirDataModel/RigActiveCellInfo.cpp @@ -193,6 +193,14 @@ void RigActiveCellInfo::clear() m_activeCellsBoundingBox.reset(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RigActiveCellInfo::isCoarseningActive() const +{ + return m_globalCellResultCount != m_globalActiveCellCount; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ReservoirDataModel/RigActiveCellInfo.h b/ApplicationCode/ReservoirDataModel/RigActiveCellInfo.h index 2719dbffb5..cbe11c9b8c 100644 --- a/ApplicationCode/ReservoirDataModel/RigActiveCellInfo.h +++ b/ApplicationCode/ReservoirDataModel/RigActiveCellInfo.h @@ -36,6 +36,7 @@ class RigActiveCellInfo : public cvf::Object size_t globalCellCount() const; size_t globalActiveCellCount() const; size_t globalCellResultCount() const; + bool isCoarseningActive() const; bool isActive(size_t globalCellIndex) const; size_t cellResultIndex(size_t globalCellIndex) const; diff --git a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp index 36516365d0..ea168688b6 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp @@ -122,9 +122,20 @@ void RigCaseCellResultsData::minMaxCellScalarValues(size_t scalarResultIndex, si size_t tranX, tranY, tranZ; if (!findTransmissibilityResults(tranX, tranY, tranZ)) return; - minMaxCellScalarValues(tranX, timeStepIndex, min, max); - minMaxCellScalarValues(tranY, timeStepIndex, min, max); - minMaxCellScalarValues(tranZ, timeStepIndex, min, max); + double tranMin; + double tranMax; + + minMaxCellScalarValues(tranX, timeStepIndex, tranMin, tranMax); + min = CVF_MIN(tranMin, min); + max = CVF_MAX(tranMax, max); + + minMaxCellScalarValues(tranY, timeStepIndex, tranMin, tranMax); + min = CVF_MIN(tranMin, min); + max = CVF_MAX(tranMax, max); + + minMaxCellScalarValues(tranZ, timeStepIndex, tranMin, tranMax); + min = CVF_MIN(tranMin, min); + max = CVF_MAX(tranMax, max); return; } @@ -738,9 +749,16 @@ void RigCaseCellResultsData::posNegClosestToZero(size_t scalarResultIndex, size_ size_t tranX, tranY, tranZ; if (findTransmissibilityResults(tranX, tranY, tranZ)) { - posNegClosestToZero(tranX, timeStepIndex, pos, neg); - posNegClosestToZero(tranY, timeStepIndex, pos, neg); - posNegClosestToZero(tranZ, timeStepIndex, pos, neg); + double traPos, traNeg; + posNegClosestToZero(tranX, timeStepIndex, traPos, traNeg); + if ( 0 < traPos && traPos < pos ) pos = traPos; + if ( neg < traNeg && traNeg < 0 ) neg = traNeg; + posNegClosestToZero(tranY, timeStepIndex, traPos, traNeg); + if ( 0 < traPos && traPos < pos ) pos = traPos; + if ( neg < traNeg && traNeg < 0 ) neg = traNeg; + posNegClosestToZero(tranZ, timeStepIndex, traPos, traNeg); + if ( 0 < traPos && traPos < pos ) pos = traPos; + if ( neg < traNeg && traNeg < 0 ) neg = traNeg; } return; diff --git a/ApplicationCode/ReservoirDataModel/RigFault.cpp b/ApplicationCode/ReservoirDataModel/RigFault.cpp index d96b5776be..6bfaba0dca 100644 --- a/ApplicationCode/ReservoirDataModel/RigFault.cpp +++ b/ApplicationCode/ReservoirDataModel/RigFault.cpp @@ -119,7 +119,7 @@ void RigFault::computeFaultFacesFromCellRanges(const RigMainGrid* mainGrid) size_t ni, nj, nk; mainGrid->neighborIJKAtCellFace(i, j, k, faceEnum, &ni, &nj, &nk); - if (ni != cvf::UNDEFINED_SIZE_T && nj != cvf::UNDEFINED_SIZE_T && nk != cvf::UNDEFINED_SIZE_T) + if (ni < mainGrid->cellCountI() && nj < mainGrid->cellCountJ() && nk < mainGrid->cellCountK()) { size_t localCellIndex = mainGrid->cellIndexFromIJK(i, j, k); size_t oppositeCellIndex = mainGrid->cellIndexFromIJK(ni, nj, nk); diff --git a/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp b/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp index 0c93dbf975..10d6ae9aaf 100644 --- a/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp +++ b/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp @@ -227,7 +227,7 @@ void RigMainGrid::calculateFaults() RigFault * unNamedFault = new RigFault; int unNamedFaultIdx = static_cast(m_faults.size()); - for (size_t gcIdx = 0 ; gcIdx < m_cells.size(); ++gcIdx) + for (int gcIdx = 0 ; gcIdx < static_cast(m_cells.size()); ++gcIdx) { if ( m_cells[gcIdx].isInvalid()) { @@ -298,8 +298,11 @@ void RigMainGrid::calculateFaults() if (gcIdx < neighborGlobalCellIdx) { - RigFault::FaultFace ff(gcIdx, cvf::StructGridInterface::FaceType(faceIdx), neighborGlobalCellIdx); - unNamedFault->faultFaces().push_back(ff); + { + RigFault::FaultFace ff(gcIdx, cvf::StructGridInterface::FaceType(faceIdx), neighborGlobalCellIdx); + unNamedFault->faultFaces().push_back(ff); + } + } else { diff --git a/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.cpp b/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.cpp index 0905772400..ec981ebc21 100644 --- a/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.cpp +++ b/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.cpp @@ -34,6 +34,7 @@ RigReservoirBuilderMock::RigReservoirBuilderMock() m_resultCount = 0; m_timeStepCount = 0; m_gridPointDimensions = cvf::Vec3st::ZERO; + m_enableWellData = true; } //-------------------------------------------------------------------------------------------------- @@ -134,10 +135,15 @@ void RigReservoirBuilderMock::appendCubeNodes(const cvf::Vec3d& min, const cvf:: void RigReservoirBuilderMock::appendCells(size_t nodeStartIndex, size_t cellCount, RigGridBase* hostGrid, std::vector& cells) { size_t activeCellIndex = 0; - size_t i; - for (i = 0; i < cellCount; i++) + long long i; + + size_t cellIndexStart = cells.size(); + cells.resize(cells.size() + cellCount); + +#pragma omp parallel for + for (i = 0; i < static_cast(cellCount); i++) { - RigCell riCell; + RigCell& riCell = cells[cellIndexStart + i]; riCell.setHostGrid(hostGrid); riCell.setCellIndex(i); @@ -152,20 +158,6 @@ void RigReservoirBuilderMock::appendCells(size_t nodeStartIndex, size_t cellCoun riCell.cornerIndices()[7] = nodeStartIndex + i * 8 + 7; riCell.setParentCellIndex(0); - - //TODO: Rewrite active cell info in mock models - /* - if (!(i % 5)) - { - riCell.setActiveIndexInMatrixModel(cvf::UNDEFINED_SIZE_T); - } - else - { - riCell.setActiveIndexInMatrixModel(activeCellIndex++); - } - */ - - cells.push_back(riCell); } } @@ -246,7 +238,10 @@ void RigReservoirBuilderMock::populateReservoir(RigCaseData* eclipseCase) eclipseCase->mainGrid()->setGridPointDimensions(m_gridPointDimensions); - addWellData(eclipseCase, eclipseCase->mainGrid()); + if (m_enableWellData) + { + addWellData(eclipseCase, eclipseCase->mainGrid()); + } addFaults(eclipseCase); @@ -317,13 +312,12 @@ bool RigReservoirBuilderMock::inputProperty(RigCaseData* eclipseCase, const QStr //-------------------------------------------------------------------------------------------------- bool RigReservoirBuilderMock::staticResult(RigCaseData* eclipseCase, const QString& result, std::vector* values) { - size_t k; + values->resize(eclipseCase->mainGrid()->cells().size()); - for (k = 0; k < eclipseCase->mainGrid()->cells().size(); k++) +#pragma omp parallel for + for (long long k = 0; k < static_cast(eclipseCase->mainGrid()->cells().size()); k++) { - { - values->push_back((k * 2) % eclipseCase->mainGrid()->cells().size()); - } + values->at(k) = (k * 2) % eclipseCase->mainGrid()->cells().size(); } return false; @@ -346,13 +340,15 @@ bool RigReservoirBuilderMock::dynamicResult(RigCaseData* eclipseCase, const QStr double scaleValue = 1.0 + resultIndex * 0.1; double offsetValue = 100 * resultIndex; - size_t k; - for (k = 0; k < eclipseCase->mainGrid()->cells().size(); k++) + values->resize(eclipseCase->mainGrid()->cells().size()); + +#pragma omp parallel for + for (long long k = 0; k < static_cast(eclipseCase->mainGrid()->cells().size()); k++) { RigCell& cell = eclipseCase->mainGrid()->cells()[k]; { double val = offsetValue + scaleValue * ( (stepIndex * 1000 + k) % eclipseCase->mainGrid()->cells().size() ); - values->push_back(val); + values->at(k) = val; } } @@ -521,3 +517,11 @@ void RigReservoirBuilderMock::addFaults(RigCaseData* eclipseCase) grid->setFaults(faults); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigReservoirBuilderMock::enableWellData(bool enableWellData) +{ + m_enableWellData = false; +} + diff --git a/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.h b/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.h index 619fb0069a..7076027264 100644 --- a/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.h +++ b/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.h @@ -48,6 +48,7 @@ class RigReservoirBuilderMock void setWorldCoordinates(cvf::Vec3d minWorldCoordinate, cvf::Vec3d maxWorldCoordinate); void setGridPointDimensions(const cvf::Vec3st& gridPointDimensions); void setResultInfo(size_t resultCount, size_t timeStepCount); + void enableWellData(bool enableWellData); size_t resultCount() const { return m_resultCount; } size_t timeStepCount() const { return m_timeStepCount; } @@ -91,6 +92,7 @@ class RigReservoirBuilderMock cvf::Vec3st m_gridPointDimensions; size_t m_resultCount; size_t m_timeStepCount; + bool m_enableWellData; std::vector m_localGridRefinements; }; diff --git a/ApplicationCode/SocketInterface/RiaCaseInfoCommands.cpp b/ApplicationCode/SocketInterface/RiaCaseInfoCommands.cpp index 201267dfb0..e81b9db3ea 100644 --- a/ApplicationCode/SocketInterface/RiaCaseInfoCommands.cpp +++ b/ApplicationCode/SocketInterface/RiaCaseInfoCommands.cpp @@ -16,9 +16,12 @@ ///////////////////////////////////////////////////////////////////////////////// #include "RiaStdInclude.h" + #include "RiaSocketCommand.h" #include "RiaSocketServer.h" #include "RiaSocketTools.h" +#include "RiaApplication.h" +#include "RiaPreferences.h" #include "RimReservoirView.h" #include "RimResultSlot.h" @@ -28,8 +31,8 @@ #include "RimWellCollection.h" #include "Rim3dOverlayInfoConfig.h" #include "RimReservoirCellResultsCacher.h" - #include "RimCase.h" + #include "RigCaseData.h" #include "RigCaseCellResultsData.h" @@ -37,6 +40,7 @@ + //-------------------------------------------------------------------------------------------------- /// OBSOLETE, to be deleted //-------------------------------------------------------------------------------------------------- @@ -128,18 +132,9 @@ class RiaGetActiveCellInfo: public RiaSocketCommand quint64 timestepByteCount = (quint64)(timestepResultCount*sizeof(qint32)); socketStream << timestepByteCount; - // Then write the data. - for (size_t tIdx = 0; tIdx < columnCount; ++tIdx) { -#if 1 // Write data as raw bytes, fast but does not handle byteswapping - server->currentClient()->write((const char *)activeCellInfo[tIdx].data(), timestepByteCount); -#else // Write data using QDataStream, does byteswapping for us. Must use QDataStream on client as well - for (size_t cIdx = 0; cIdx < activeCellInfo[tIdx].size(); ++cIdx) - { - socketStream << activeCellInfo[tIdx][cIdx]; - } -#endif + RiaSocketTools::writeBlockData(server, server->currentClient(), (const char *)activeCellInfo[tIdx].data(), timestepByteCount); } return true; diff --git a/ApplicationCode/SocketInterface/RiaGeometryCommands.cpp b/ApplicationCode/SocketInterface/RiaGeometryCommands.cpp index 2ec5878cb6..c76bc690ae 100644 --- a/ApplicationCode/SocketInterface/RiaGeometryCommands.cpp +++ b/ApplicationCode/SocketInterface/RiaGeometryCommands.cpp @@ -34,6 +34,9 @@ #include "RigCaseCellResultsData.h" #include +#include "RiaApplication.h" +#include "RiaPreferences.h" + //-------------------------------------------------------------------------------------------------- @@ -84,11 +87,14 @@ class RiaGetCellCenters : public RiaSocketCommand // dv(2) = cellCountK; // dv(3) = 3; - std::vector cellCenterValues(doubleValueCount); cvf::Vec3d cornerVerts[8]; - quint64 coordCount = 0; + size_t blockByteCount = cellCount * sizeof(double); + std::vector doubleValues(blockByteCount); + for (int coordIdx = 0; coordIdx < 3; coordIdx++) { + quint64 valueIndex = 0; + for (size_t k = 0; k < cellCountK; k++) { for (size_t j = 0; j < cellCountJ; j++) @@ -98,15 +104,15 @@ class RiaGetCellCenters : public RiaSocketCommand size_t localCellIdx = rigGrid->cellIndexFromIJK(i, j, k); cvf::Vec3d center = rigGrid->cell(localCellIdx).center(); - cellCenterValues[coordCount++] = center[coordIdx]; + doubleValues[valueIndex++] = center[coordIdx]; } } } - } - CVF_ASSERT(coordCount == doubleValueCount); + CVF_ASSERT(valueIndex == cellCount); - server->currentClient()->write((const char *)cellCenterValues.data(), byteCount); + RiaSocketTools::writeBlockData(server, server->currentClient(), (const char *)doubleValues.data(), blockByteCount); + } return true; } @@ -149,6 +155,11 @@ class RiaGetActiveCellCenters : public RiaSocketCommand size_t activeCellCount = actCellInfo->globalActiveCellCount(); size_t doubleValueCount = activeCellCount * 3; + socketStream << (quint64)activeCellCount; + quint64 byteCount = doubleValueCount * sizeof(double); + socketStream << byteCount; + + // This structure is supposed to be received by Octave using a NDArray. The ordering of this loop is // defined by the ordering of the receiving NDArray // @@ -159,27 +170,25 @@ class RiaGetActiveCellCenters : public RiaSocketCommand // dv(0) = coordCount; // dv(1) = 3; - std::vector cellCenterValues(doubleValueCount); - quint64 coordCount = 0; + size_t blockByteCount = activeCellCount * sizeof(double); + std::vector doubleValues(blockByteCount); + for (int coordIdx = 0; coordIdx < 3; coordIdx++) { + quint64 valueIndex = 0; + for (size_t globalCellIdx = 0; globalCellIdx < mainGrid->cells().size(); globalCellIdx++) { if (!actCellInfo->isActive(globalCellIdx)) continue; cvf::Vec3d center = mainGrid->cells()[globalCellIdx].center(); - cellCenterValues[coordCount++] = center[coordIdx]; + doubleValues[valueIndex++] = center[coordIdx]; } - } - CVF_ASSERT(coordCount == doubleValueCount); - - socketStream << (quint64)activeCellCount; - quint64 byteCount = doubleValueCount * sizeof(double); - socketStream << byteCount; - - server->currentClient()->write((const char *)cellCenterValues.data(), byteCount); + CVF_ASSERT(valueIndex == activeCellCount); + RiaSocketTools::writeBlockData(server, server->currentClient(), (const char *)doubleValues.data(), blockByteCount); + } return true; } @@ -241,15 +250,18 @@ class RiaGetCellCorners : public RiaSocketCommand // dv(3) = 8; // dv(4) = 3; - std::vector cellCornerValues(doubleValueCount); cvf::Vec3d cornerVerts[8]; - quint64 coordCount = 0; + size_t blockByteCount = cellCount * sizeof(double); + std::vector doubleValues(blockByteCount); + for (int coordIdx = 0; coordIdx < 3; coordIdx++) { for (size_t cornerIdx = 0; cornerIdx < 8; cornerIdx++) { size_t cornerIndexMapping = cellCornerMappingEclipse[cornerIdx]; + quint64 valueIndex = 0; + for (size_t k = 0; k < cellCountK; k++) { for (size_t j = 0; j < cellCountJ; j++) @@ -259,15 +271,17 @@ class RiaGetCellCorners : public RiaSocketCommand size_t localCellIdx = rigGrid->cellIndexFromIJK(i, j, k); rigGrid->cellCornerVertices(localCellIdx, cornerVerts); - cellCornerValues[coordCount++] = cornerVerts[cornerIndexMapping][coordIdx]; + doubleValues[valueIndex++] = cornerVerts[cornerIndexMapping][coordIdx]; } } } + + CVF_ASSERT(valueIndex == cellCount); + + RiaSocketTools::writeBlockData(server, server->currentClient(), (const char *)doubleValues.data(), blockByteCount); } } - server->currentClient()->write((const char *)cellCornerValues.data(), byteCount); - return true; } }; @@ -310,6 +324,10 @@ class RiaGetActiveCellCorners : public RiaSocketCommand size_t activeCellCount = actCellInfo->globalActiveCellCount(); size_t doubleValueCount = activeCellCount * 3 * 8; + socketStream << (quint64)activeCellCount; + quint64 byteCount = doubleValueCount * sizeof(double); + socketStream << byteCount; + // This structure is supposed to be received by Octave using a NDArray. The ordering of this loop is // defined by the ordering of the receiving NDArray // @@ -321,31 +339,32 @@ class RiaGetActiveCellCorners : public RiaSocketCommand // dv(1) = 8; // dv(2) = 3; - std::vector cellCornerValues(doubleValueCount); cvf::Vec3d cornerVerts[8]; - quint64 coordCount = 0; + size_t blockByteCount = activeCellCount * sizeof(double); + std::vector doubleValues(blockByteCount); + for (int coordIdx = 0; coordIdx < 3; coordIdx++) { for (size_t cornerIdx = 0; cornerIdx < 8; cornerIdx++) { size_t cornerIndexMapping = cellCornerMappingEclipse[cornerIdx]; + quint64 valueIndex = 0; + for (size_t globalCellIdx = 0; globalCellIdx < mainGrid->cells().size(); globalCellIdx++) { if (!actCellInfo->isActive(globalCellIdx)) continue; mainGrid->cellCornerVertices(globalCellIdx, cornerVerts); - cellCornerValues[coordCount++] = cornerVerts[cornerIndexMapping][coordIdx]; + doubleValues[valueIndex++] = cornerVerts[cornerIndexMapping][coordIdx]; } - } - } - socketStream << (quint64)activeCellCount; - quint64 byteCount = doubleValueCount * sizeof(double); - socketStream << byteCount; + CVF_ASSERT(valueIndex == activeCellCount); - server->currentClient()->write((const char *)cellCornerValues.data(), byteCount); + RiaSocketTools::writeBlockData(server, server->currentClient(), (const char *)doubleValues.data(), blockByteCount); + } + } return true; } diff --git a/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp b/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp index 40dc5d2efd..fa5fc419fd 100644 --- a/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp +++ b/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp @@ -40,6 +40,9 @@ #include "Rim3dOverlayInfoConfig.h" #include +#include "RiaApplication.h" +#include "RiaPreferences.h" +#include "RiaSocketDataTransfer.h" //-------------------------------------------------------------------------------------------------- @@ -143,48 +146,60 @@ class RiaGetActiveCellProperty: public RiaSocketCommand socketStream << timestepByteCount ; // Then write the data. + size_t valueCount = RiaSocketDataTransfer::maximumValueCountInBlock(); + std::vector values(valueCount); + size_t valueIndex = 0; size_t globalCellCount = activeInfo->globalCellCount(); for (size_t tIdx = 0; tIdx < requestedTimesteps.size(); ++tIdx) { + std::vector& doubleValues = scalarResultFrames->at(requestedTimesteps[tIdx]); for (size_t gcIdx = 0; gcIdx < globalCellCount; ++gcIdx) { size_t resultIdx = activeInfo->cellResultIndex(gcIdx); - if (resultIdx != cvf::UNDEFINED_SIZE_T) + if (resultIdx == cvf::UNDEFINED_SIZE_T) continue; + + if (resultIdx < doubleValues.size()) { - if (resultIdx < scalarResultFrames->at(requestedTimesteps[tIdx]).size()) + if (doubleValues.size() == activeInfo->globalCellCount()) { - socketStream << scalarResultFrames->at(requestedTimesteps[tIdx])[resultIdx]; + // When reading data from input text files, result data is read for all grid cells + // Read out values from data vector using global cell index instead of active cell result index + // When data is written back to ResInsight using RiaSetActiveCellProperty, the resulting + // data vector will have activeCellCount data values, which is potentially smaller + // than total number of cells + values[valueIndex] = doubleValues[gcIdx]; } else { - socketStream << HUGE_VAL; + values[valueIndex] = doubleValues[resultIdx]; } } + else + { + values[valueIndex] = HUGE_VAL; + } + + valueIndex++; + if (valueIndex >= valueCount) + { + if (!RiaSocketTools::writeBlockData(server, server->currentClient(), (const char *)values.data(), valueIndex * sizeof(double))) + { + return false; + } + + valueIndex = 0; + } } } -#if 0 - // This aproach is faster but does not handle coarsening - size_t timestepResultCount = scalarResultFrames->front().size(); - quint64 timestepByteCount = (quint64)(timestepResultCount*sizeof(double)); - socketStream << timestepByteCount ; - - // Then write the data. - for (size_t tIdx = 0; tIdx < requestedTimesteps.size(); ++tIdx) + // Write remaining data + if (!RiaSocketTools::writeBlockData(server, server->currentClient(), (const char *)values.data(), valueIndex * sizeof(double))) { -#if 1 // Write data as raw bytes, fast but does not handle byteswapping - server->currentClient()->write((const char *)scalarResultFrames->at(requestedTimesteps[tIdx]).data(), timestepByteCount); // Raw print of data. Fast but no platform conversion -#else // Write data using QDataStream, does byteswapping for us. Must use QDataStream on client as well - for (size_t cIdx = 0; cIdx < scalarResultFrames->at(requestedTimesteps[tIdx]).size(); ++cIdx) - { - socketStream << scalarResultFrames->at(tIdx)[cIdx]; - } -#endif + return false; } -#endif - } + } return true; } }; @@ -304,10 +319,6 @@ class RiaGetGridProperty: public RiaSocketCommand quint64 timestepCount = (quint64)requestedTimesteps.size(); socketStream << timestepCount; - size_t doubleValueCount = cellCountI * cellCountJ * cellCountK * timestepCount * sizeof(double); - std::vector values(doubleValueCount); - size_t valueIdx = 0; - for (size_t tsIdx = 0; tsIdx < timestepCount; tsIdx++) { cvf::ref cellCenterDataAccessObject = rimCase->reservoirData()->dataAccessObject(rigGrid, porosityModelEnum, requestedTimesteps[tsIdx], scalarResultIndex); @@ -316,6 +327,9 @@ class RiaGetGridProperty: public RiaSocketCommand continue; } + size_t valueCount = RiaSocketDataTransfer::maximumValueCountInBlock(); + std::vector values(valueCount); + size_t valueIndex = 0; for (size_t cellIdx = 0; cellIdx < rigGrid->cellCount(); cellIdx++) { double cellValue = cellCenterDataAccessObject->cellScalar(cellIdx); @@ -323,11 +337,25 @@ class RiaGetGridProperty: public RiaSocketCommand { cellValue = 0.0; } - values[valueIdx++] = cellValue; + values[valueIndex++] = cellValue; + + if (valueIndex >= valueCount) + { + if (!RiaSocketTools::writeBlockData(server, server->currentClient(), (const char *)values.data(), valueIndex * sizeof(double))) + { + return false; + } + + valueIndex = 0; + } } - } - server->currentClient()->write((const char *)values.data(), doubleValueCount); + // Write remaining data + if (!RiaSocketTools::writeBlockData(server, server->currentClient(), (const char *)values.data(), valueIndex * sizeof(double))) + { + return false; + } + } return true; } @@ -553,16 +581,18 @@ class RiaSetActiveCellProperty: public RiaSocketCommand internalMatrixData = m_scalarResultsToAdd->at(m_requestedTimesteps[m_currentTimeStepNumberToRead]).data(); } -#if 1 // Use raw data transfer. Faster. - bytesRead = currentClient->read((char*)(internalMatrixData), m_bytesPerTimeStepToRead); -#else - for (size_t cIdx = 0; cIdx < cellCountFromOctave; ++cIdx) + QStringList errorMessages; + if (!RiaSocketDataTransfer::readBlockDataFromSocket(currentClient, (char*)(internalMatrixData), m_bytesPerTimeStepToRead, errorMessages)) { - socketStream >> internalMatrixData[cIdx]; + for (int i = 0; i < errorMessages.size(); i++) + { + server->errorMessageDialog()->showMessage(errorMessages[i]); + } - if (socketStream.status() == QDataStream::Ok) bytesRead += sizeof(double); + currentClient->abort(); + return true; } -#endif + // Map data from active to result index based container ( Coarsening is active) if (isCoarseningActive) { @@ -577,12 +607,6 @@ class RiaSetActiveCellProperty: public RiaSocketCommand } } - if ((int)m_bytesPerTimeStepToRead != bytesRead) - { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + - RiaSocketServer::tr("Could not read binary double data properly from socket")); - } - ++m_currentTimeStepNumberToRead; } @@ -897,8 +921,17 @@ class RiaSetGridProperty : public RiaSocketCommand std::vector doubleValues(cellCountFromOctave); - qint64 bytesRead = currentClient->read((char*)(doubleValues.data()), m_bytesPerTimeStepToRead); - size_t doubleValueIndex = 0; + QStringList errorMessages; + if (!RiaSocketDataTransfer::readBlockDataFromSocket(currentClient, (char*)(doubleValues.data()), m_bytesPerTimeStepToRead, errorMessages)) + { + for (int i = 0; i < errorMessages.size(); i++) + { + server->errorMessageDialog()->showMessage(errorMessages[i]); + } + + currentClient->abort(); + return true; + } cvf::ref cellCenterDataAccessObject = m_currentReservoir->reservoirData()->dataAccessObject(grid, m_porosityModelEnum, m_requestedTimesteps[m_currentTimeStepNumberToRead], m_currentScalarIndex); diff --git a/ApplicationCode/SocketInterface/RiaSocketDataTransfer.cpp b/ApplicationCode/SocketInterface/RiaSocketDataTransfer.cpp new file mode 100644 index 0000000000..0d2ec8879f --- /dev/null +++ b/ApplicationCode/SocketInterface/RiaSocketDataTransfer.cpp @@ -0,0 +1,113 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA, Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiaSocketDataTransfer.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaSocketDataTransfer::writeBlockDataToSocket(QTcpSocket* socket, const char* data, quint64 bytesToWrite, QStringList& errorMessages) +{ + quint64 bytesWritten = 0; + int blockCount = 0; + + quint64 maxBlockSize = maximumValueCountInBlock() * sizeof(double); + + while (bytesWritten < bytesToWrite) + { + quint64 byteCountToWrite = qMin(bytesToWrite - bytesWritten, maxBlockSize); + + qint64 actuallyBytesWritten = socket->write(data + bytesWritten, byteCountToWrite); + if (actuallyBytesWritten < 0) + { + errorMessages.push_back("Error detected when writing data, error string from socket"); + errorMessages.push_back(socket->errorString()); + + return false; + } + + bytesWritten += actuallyBytesWritten; + + blockCount++; + } + + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaSocketDataTransfer::readBlockDataFromSocket(QTcpSocket* socket, char* data, quint64 bytesToRead, QStringList& errorMessages) +{ + quint64 bytesRead = 0; + + quint64 maxBlockSize = maximumValueCountInBlock() * sizeof(double); + + while (bytesRead < bytesToRead) + { + if (socket->bytesAvailable()) + { + quint64 byteCountToRead = bytesToRead - bytesRead; + byteCountToRead = qMin(byteCountToRead, maxBlockSize); + + qint64 actuallyBytesRead = socket->read(data + bytesRead, byteCountToRead); + if (actuallyBytesRead < 0) + { + errorMessages.push_back("Error detected when reading data, error string from socket"); + errorMessages.push_back(socket->errorString()); + + return false; + } + + bytesRead += actuallyBytesRead; + +#ifdef octave_oct_h + //octave_stdout << "Byte read " << bytesRead << " of a total of "<< bytesToRead << "\n"; +#endif + } + else + { + if (!socket->waitForReadyRead()) + { + errorMessages.push_back("Waited for data for %1 milli seconds."); + errorMessages.push_back(socket->errorString()); + + return false; + } + } + + // Allow Octave process to end a long running Octave function +#ifdef octave_oct_h + OCTAVE_QUIT; +#endif + + } + + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RiaSocketDataTransfer::maximumValueCountInBlock() +{ + return 20000; +} + + diff --git a/ApplicationCode/SocketInterface/RiaSocketDataTransfer.h b/ApplicationCode/SocketInterface/RiaSocketDataTransfer.h new file mode 100644 index 0000000000..7c16beb8aa --- /dev/null +++ b/ApplicationCode/SocketInterface/RiaSocketDataTransfer.h @@ -0,0 +1,36 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA, Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include +#include + +//================================================================================================== +/// Utility class used for transfer of data using QTcpSocket +/// +/// As the compile configuration for octave plugins is quite complex, +// the octave plugins includes the cpp-file to be able to compile only one file per plugin +//================================================================================================== +class RiaSocketDataTransfer +{ +public: + static size_t maximumValueCountInBlock(); + +public: + static bool writeBlockDataToSocket(QTcpSocket* socket, const char* data, quint64 bytesToWrite, QStringList& errorMessages); + static bool readBlockDataFromSocket(QTcpSocket* socket, char* data, quint64 bytesToRead, QStringList& errorMessages); +}; diff --git a/ApplicationCode/SocketInterface/RiaSocketTools.cpp b/ApplicationCode/SocketInterface/RiaSocketTools.cpp index cc53f26824..967c0b43b4 100644 --- a/ApplicationCode/SocketInterface/RiaSocketTools.cpp +++ b/ApplicationCode/SocketInterface/RiaSocketTools.cpp @@ -16,6 +16,10 @@ ///////////////////////////////////////////////////////////////////////////////// #include "RiaStdInclude.h" + +#include "RiaApplication.h" +#include "RiaPreferences.h" + #include "RiaSocketTools.h" #include "RiaSocketServer.h" #include "RimCase.h" @@ -34,6 +38,9 @@ #include "RimInputPropertyCollection.h" +#include "RiaSocketDataTransfer.h" + +#include //-------------------------------------------------------------------------------------------------- /// @@ -98,4 +105,28 @@ void RiaSocketTools::getCaseInfoFromCase(RimCase* rimCase, qint64& caseId, QStri } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaSocketTools::writeBlockData(RiaSocketServer* server, QTcpSocket* socket, const char* data, quint64 bytesToWrite) +{ + cvf::Timer timer; + + QStringList errorMessages; + bool writeSucceded = RiaSocketDataTransfer::writeBlockDataToSocket(socket, data, bytesToWrite, errorMessages); + if (server) + { + for (int i = 0; i < errorMessages.size(); i++) + { + server->errorMessageDialog()->showMessage(errorMessages[i]); + } + +// double totalTimeMS = timer.time() * 1000.0; +// QString resultInfo = QString("Total time '%1 ms'").arg(totalTimeMS); +// +// server->errorMessageDialog()->showMessage(resultInfo); + } + + return writeSucceded; +} diff --git a/ApplicationCode/SocketInterface/RiaSocketTools.h b/ApplicationCode/SocketInterface/RiaSocketTools.h index 1baeb5a9fc..b331799e2e 100644 --- a/ApplicationCode/SocketInterface/RiaSocketTools.h +++ b/ApplicationCode/SocketInterface/RiaSocketTools.h @@ -17,6 +17,7 @@ class RimCase; class RiaSocketServer; +class QTcpSocket; #define PMonLog( MessageString ) RiuMainWindow::instance()->processMonitor()->addStringToLog( MessageString ); @@ -25,4 +26,6 @@ class RiaSocketTools public: static RimCase* findCaseFromArgs(RiaSocketServer* server, const QList& args); static void getCaseInfoFromCase(RimCase* rimCase, qint64& caseId, QString& caseName, QString& caseType, qint64& caseGroupId); + + static bool writeBlockData(RiaSocketServer* server, QTcpSocket* socket, const char* data, quint64 bytesToWrite); }; diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index 930a0c337c..a1fe0b204e 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -43,7 +43,6 @@ #include "RiuMultiCaseImportDialog.h" #include "RiaPreferences.h" -#include "RiuPreferencesDialog.h" #include "RigCaseCellResultsData.h" @@ -63,6 +62,7 @@ #include "RimCalcScript.h" #include "RimTools.h" #include "RiaRegressionTest.h" +#include "cafPdmUiPropertyDialog.h" @@ -199,6 +199,7 @@ void RiuMainWindow::createActions() m_mockModelAction = new QAction("&Mock Model", this); m_mockResultsModelAction = new QAction("Mock Model With &Results", this); m_mockLargeResultsModelAction = new QAction("Large Mock Model", this); + m_mockModelCustomizedAction = new QAction("Customized Mock Model", this); m_mockInputModelAction = new QAction("Input Mock Model", this); m_snapshotToFile = new QAction(QIcon(":/SnapShotSave.png"), "Snapshot To File", this); @@ -226,6 +227,7 @@ void RiuMainWindow::createActions() connect(m_mockModelAction, SIGNAL(triggered()), SLOT(slotMockModel())); connect(m_mockResultsModelAction, SIGNAL(triggered()), SLOT(slotMockResultsModel())); connect(m_mockLargeResultsModelAction, SIGNAL(triggered()), SLOT(slotMockLargeResultsModel())); + connect(m_mockModelCustomizedAction, SIGNAL(triggered()), SLOT(slotMockModelCustomized())); connect(m_mockInputModelAction, SIGNAL(triggered()), SLOT(slotInputMockModel())); connect(m_snapshotToFile, SIGNAL(triggered()), SLOT(slotSnapshotToFile())); @@ -386,6 +388,7 @@ void RiuMainWindow::createMenus() testMenu->addAction(m_mockModelAction); testMenu->addAction(m_mockResultsModelAction); testMenu->addAction(m_mockLargeResultsModelAction); + testMenu->addAction(m_mockModelCustomizedAction); testMenu->addAction(m_mockInputModelAction); testMenu->addSeparator(); testMenu->addAction(m_createCommandObject); @@ -660,7 +663,8 @@ void RiuMainWindow::refreshAnimationActions() { if (app->activeReservoirView()->cellResult()->hasDynamicResult() || app->activeReservoirView()->propertyFilterCollection()->hasActiveDynamicFilters() - || app->activeReservoirView()->wellCollection()->hasVisibleWellPipes()) + || app->activeReservoirView()->wellCollection()->hasVisibleWellPipes() + || app->activeReservoirView()->cellResult()->isTernarySaturationSelected()) { std::vector timeStepDates = app->activeReservoirView()->currentGridCellResults()->cellResults()->timeStepDates(0); bool showHoursAndMinutes = false; @@ -845,8 +849,6 @@ void RiuMainWindow::slotMockModel() { RiaApplication* app = RiaApplication::instance(); app->createMockModel(); - - //m_mainViewer->setDefaultView(); } //-------------------------------------------------------------------------------------------------- @@ -856,8 +858,6 @@ void RiuMainWindow::slotMockResultsModel() { RiaApplication* app = RiaApplication::instance(); app->createResultsMockModel(); - - //m_mainViewer->setDefaultView(); } @@ -870,6 +870,14 @@ void RiuMainWindow::slotMockLargeResultsModel() app->createLargeResultsMockModel(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMainWindow::slotMockModelCustomized() +{ + RiaApplication* app = RiaApplication::instance(); + app->createMockModelCustomized(); +} //-------------------------------------------------------------------------------------------------- /// @@ -1216,8 +1224,8 @@ void RiuMainWindow::slotShowPerformanceInfo(bool enable) void RiuMainWindow::slotEditPreferences() { RiaApplication* app = RiaApplication::instance(); - RiuPreferencesDialog preferencesDialog(this, app->preferences(), "Preferences"); - if (preferencesDialog.exec() == QDialog::Accepted) + caf::PdmUiPropertyDialog propertyDialog(this, app->preferences(), "Preferences"); + if (propertyDialog.exec() == QDialog::Accepted) { // Write preferences using QSettings and apply them to the application app->writeFieldsToApplicationStore(app->preferences()); @@ -1446,9 +1454,9 @@ void RiuMainWindow::slotOpenMultipleCases() if (1) { - gridFileNames += "Result Mock Debug Model With Results"; - gridFileNames += "Result Mock Debug Model With Results"; - gridFileNames += "Result Mock Debug Model With Results"; + gridFileNames += RimDefines::mockModelBasicWithResults(); + gridFileNames += RimDefines::mockModelBasicWithResults(); + gridFileNames += RimDefines::mockModelBasicWithResults(); } else { @@ -1765,7 +1773,7 @@ void RiuMainWindow::slotShowRegressionTestDialog() RiaApplication* app = RiaApplication::instance(); app->readFieldsFromApplicationStore(®TestConfig); - RiuPreferencesDialog regressionTestDialog(this, ®TestConfig, "Regression Test"); + caf::PdmUiPropertyDialog regressionTestDialog(this, ®TestConfig, "Regression Test"); if (regressionTestDialog.exec() == QDialog::Accepted) { // Write preferences using QSettings and apply them to the application diff --git a/ApplicationCode/UserInterface/RiuMainWindow.h b/ApplicationCode/UserInterface/RiuMainWindow.h index 2b92f9a7b4..ae3f922af3 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.h +++ b/ApplicationCode/UserInterface/RiuMainWindow.h @@ -154,6 +154,7 @@ class RiuMainWindow : public QMainWindow QAction* m_mockModelAction; QAction* m_mockResultsModelAction; QAction* m_mockLargeResultsModelAction; + QAction* m_mockModelCustomizedAction; QAction* m_mockInputModelAction; QAction* m_snapshotToFile; @@ -243,6 +244,7 @@ private slots: void slotMockModel(); void slotMockResultsModel(); void slotMockLargeResultsModel(); + void slotMockModelCustomized(); void slotInputMockModel(); // Windows slots diff --git a/ApplicationCode/UserInterface/RiuPreferencesDialog.cpp b/ApplicationCode/UserInterface/RiuPreferencesDialog.cpp deleted file mode 100644 index 7a094776c8..0000000000 --- a/ApplicationCode/UserInterface/RiuPreferencesDialog.cpp +++ /dev/null @@ -1,67 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS -// -// 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 -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RiaStdInclude.h" -#include "RiuPreferencesDialog.h" - -#include "cafAppEnum.h" -#include "cafPdmObject.h" - -#include "RimUiTreeModelPdm.h" -#include "cafPdmUiPropertyView.h" - - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuPreferencesDialog::RiuPreferencesDialog(QWidget* parent, caf::PdmObject* object, const QString& windowTitle) - : QDialog(parent) -{ - CVF_ASSERT(object); - - m_pdmObject = object; - m_windowTitle = windowTitle; - - setupUi(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuPreferencesDialog::setupUi() -{ - setWindowTitle(m_windowTitle); - - m_pdmUiPropertyView = new caf::PdmUiPropertyView(this); - - QVBoxLayout* dialogLayout = new QVBoxLayout; - setLayout(dialogLayout); - - dialogLayout->addWidget(m_pdmUiPropertyView); - m_pdmUiPropertyView->showProperties(m_pdmObject); - - // Buttons - QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - - dialogLayout->addWidget(buttonBox); - - this->resize(400, 200); -} diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index b2af5cf05e..354cc30af3 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -742,3 +742,19 @@ void RiuViewer::mousePressEvent(QMouseEvent* event) m_lastMousePressPosition = event->pos(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::addOverlayItem(cvf::OverlayItem* overlayItem) +{ + m_renderingSequence->firstRendering()->addOverlayItem(overlayItem); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::removeOverlayItem(cvf::OverlayItem* overlayItem) +{ + m_renderingSequence->firstRendering()->removeOverlayItem(overlayItem); +} + diff --git a/ApplicationCode/UserInterface/RiuViewer.h b/ApplicationCode/UserInterface/RiuViewer.h index eb89a5cedd..7e881a1464 100644 --- a/ApplicationCode/UserInterface/RiuViewer.h +++ b/ApplicationCode/UserInterface/RiuViewer.h @@ -34,6 +34,7 @@ class QCDEStyle; namespace cvf { class Part; + class OverlayItem; } //================================================================================================== @@ -64,6 +65,10 @@ class RiuViewer : public caf::Viewer void setHistogramPercentiles(double pmin, double pmax, double mean); void showAnimationProgress(bool enable); + + void addOverlayItem(cvf::OverlayItem* overlayItem); + void removeOverlayItem(cvf::OverlayItem* overlayItem); + public slots: virtual void slotSetCurrentFrame(int frameIndex); diff --git a/CMakeLists.txt b/CMakeLists.txt index 494da32e0d..a41fddb4da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,8 +93,30 @@ include (${QT_USE_FILE}) find_package( OpenGL ) ################################################################################ -# CeeViz -################################################################################ +# Vizualization Framework +################################################################################ + +# Allow use of non-threadsafe reference counter in cvf::Object on systems with no atomics support +if (CMAKE_COMPILER_IS_GNUCC) + + if (NOT DEFINED HAVE_GCC_SYNC_FUNCTIONS) + check_c_source_compiles("int main(int argc, char **argv) { + int a; + __sync_add_and_fetch(&a, 1); + __sync_fetch_and_add(&a, 1); + __sync_sub_and_fetch(&a, 1); + __sync_fetch_and_sub(&a, 1); }" HAVE_GCC_SYNC_FUNCTIONS) + endif() + + if (HAVE_GCC_SYNC_FUNCTIONS) + message("GCC synchronization functions detected") + else() + message("GCC synchronization functions NOT detected, fallback to non threadsafe reference counting") + add_definitions(-DCVF_USE_NON_THREADSAFE_REFERENCE_COUNT) + endif() + +endif() + add_subdirectory(${VIZ_MODULES_FOLDER_NAME}/LibCore) add_subdirectory(${VIZ_MODULES_FOLDER_NAME}/LibGeometry) add_subdirectory(${VIZ_MODULES_FOLDER_NAME}/LibRender) @@ -111,7 +133,7 @@ include_directories( ################################################################################ -# Ceetron Application Framework +# Application Framework ################################################################################ add_subdirectory(Fwk/AppFwk/cafProjectDataModel) diff --git a/Documentation/UsersGuide/Faults.md b/Documentation/UsersGuide/Faults.md index 7c19393aa1..5ce0bc92f7 100644 --- a/Documentation/UsersGuide/Faults.md +++ b/Documentation/UsersGuide/Faults.md @@ -3,40 +3,84 @@ ----- ## Faults -ResInsight can import faults from `*.DATA` files, and is available in the ![](images/draw_style_faults_24x24.png) **Faults** item in the **Project Tree**. The imported faults are ordered in ascending order based on name. +ResInsight will detect all the cell faces with no geometrically matching neighbors, and display them as *Faults*. +This means that the are drawn in special ways, and that their visual appearance can be controlled separately from the rest of the grid. -As import of faults can be time consuming, reading of faults can be disabled from **Preferences -> Read fault data** +### Fault Names and NNC -A fault is defined as a set of cell faces. When clicking on a fault, the fault name is displayed in **Result Info**. Results can be mapped onto a fault, and **Dynamic Face Selection** controls the cell result mapping onto faults. Faults are given a color on import, and this color can be controlled by activating the fault and select **Fault color**. +#### Import of Fault info from `*.DATA`-files +If enabled, ResInsight will also import fault information from the `*.DATA` files and use this information to group the detected faces into named items which is available in the ![](images/draw_style_faults_24x24.png) **Faults** item in the **Project Tree**. The imported faults are ordered in ascending order based on their name. -When clicking on a NNC, the relevant data for this NNC is displayed in the **Result Info**. The static result **TRANSXYZ** can be mapped onto NNC geometry. +> +***Note:*** As import of faults can be time consuming, reading of faults can be disabled from **Preferences -> Read fault data** -ResInsight will detect all cell faces with no matching neighbor. All detected cell faces are compared to faults imported from disk, and if no fault face is defined for a cell face, the cell face is added to a fault called **Undefined grid faults**. +#### Undefined grid faults +All the detected cell faces are compared to the faults imported from the `*.DATA` file in order to group them. If a particular face is *not* found among the fault faces defined in the `*.DATA` file or it's opposite face, the cell face is added to a fault called **Undefined grid faults**. This particular Fault will always be present, even if reading of the `*.DATA` file is disabled. -### Toolbar control +#### Fault color + +Each named Fault is given a color on import. This color can be controlled by selecting the fault and edit its **Fault color** in the **Property Editor.** + +#### NNC visualization +ResInsight will read Non Neighbor Connections from the Eclipse output file (`*.INIT`), and create explicit visualizations of those witch have a common surface area. These NNC's are then sorted onto the Fault's and their visibility is controlled from the **Property Editor** of the **Faults** Item in the **Project Tree**. + +The color of the NNC faces are set to be a bit lighter than their corresponding named fault, and can not be controlled directly. + +Currently the only result property that is mapped onto the NNC is the static TRANSXYZ property which displays the transmissibility associated to each face. + +### Picking info + +When clicking on a cell face that is member of a fault, the fault name is displayed in the **Result Info** window, along with cell, and result property info. + +When clicking on a NNC, the relevant data for this NNC is displayed. + +### Fault visualization options + + +#### Toolbar control Visualization mode and mesh lines can be controlled from the toolbar. -- ![](images/draw_style_faults_24x24.png) Toggle button to control faults only visualization mode -- ![](images/draw_style_surface_24x24.png) Shows surface visualization -- ![](images/draw_style_surface_w_fault_mesh_24x24.png) Shows mesh lines on faults +- ![](images/draw_style_faults_24x24.png) **Faults-Only** visualization mode. +
When turned on, this option hides all the grid cells, and shows only the fault faces in the reservoir limited by the applied range and property filters. (Unless **Show faults outside filters** are turned on. See below.) +- ![](images/draw_style_surface_24x24.png) Turns faces on and mesh off +- ![](images/draw_style_surface_w_fault_mesh_24x24.png) Turns on all faces, and shows meshlines on faults only. +
This is a useful method to highlight the faults in your reservoir, because the faults stands out with black outlining. - ![](images/draw_style_faults_label_24x24.png) Shows labels for faults -### Common Fault Options -By clicking the ![](images/draw_style_faults_24x24.png) **Faults** item in the **Project Tree**, the following options are displayed: +#### Common Fault Options +By clicking the ![](images/draw_style_faults_24x24.png) **Faults** item in the **Project Tree**, the following options common to all the faults are displayed: ![](images/FaultProperties.png) - -- **Show labels**: Displays one label per fault with fault name +##### Fault labels +- **Show labels**: Displays one label per fault with the name defined in the `*.DATA`-file - **Label color**: Defines the label color -- **Show faults outside filters**: Default behavior is to hide faults outside filters. Turning this option on, will display faults outside filter region. -- **Show results on faults**: Map currently selected result onto fault. **Dynamic Face Selection** controls which cell results to map onto faults. -- **Show NNCs**: Displays non neighborhood connections (see details below) +##### Fault options +- **Show faults outside filters**: Turning this option on, will display faults outside the filter region, making the fault visualization completely ignore the Range and Property filters in action. +- **Show results on faults**: This toggle controls whether to show the selected result property on the faults or not. This should normally be left on. +- **Show NNCs**: Toggles whether to display the Non Neighbor Connections, or not. + +##### Fault Face Visibility +This group of options controls the visibility of the fault faces. Since they work together, and in some cases are overridden by the system, they can be a bit confusing. + +First of all. These options are only available in **Faults-only** visualization mode. ( See *Toolbar Control* above) When not in **Faults-Only** mode, ResInsight overrides the options, and the controls are inactive. + +Secondly: The option you would normally want to adjust is **Dynamic Face Selection** (See below). + +- **Show defined faces**: Displays the fault cell faces that are defined on the Eclipse input file (`*.DATA`) +- **Show opposite faces**: Displays the opposite fault cell faces from what is defined on the input file, based on IJK neighbors. +
*These two options should normally be left **On***.
They are useful when investigating the exact faults information provided on the `*.DATA` file. +
If you need to use them, it is normally wise to set the **Dynamic Face Selection** to "Show Both" + +######Dynamic Face Selection: + +At one particular position on a fault there are usually two cells competing for your attention: The cell closer to you as the viewer, or the one further from you. When showing results, this becomes important because these two cell faces have different result property values, and thus color. + +This option controls which of the two cell faces you actually can see: The one behind the fault, or the one in front of the fault. There is also an option of showing both, which will give you an undefined mixture, making it hard to be certain what you see. + +This means that ResInsight turns on or off the faces based on your view position and this option to make sure that you always see the faces (and thus the result property) you request. -- **Show defined faces**: Displays the defined fault cell faces -- **Show opposite faces**: Displays the opposite fault cell faces based on IJK neighbor data -- **Dynamic Face Selection**: Controls mapping of cell results onto a fault, either from cell in front of fault, from cell behind fault or both. ------ [ Contents ](UsersGuide.md#contents) diff --git a/Documentation/UsersGuide/ReservoirViews.md b/Documentation/UsersGuide/ReservoirViews.md index a6fde28cae..2a9df5430b 100644 --- a/Documentation/UsersGuide/ReservoirViews.md +++ b/Documentation/UsersGuide/ReservoirViews.md @@ -13,6 +13,11 @@ Below is a description of the most important View settings and their properties. The **Cell Result** item defines which Eclipse property the 3D View uses for the main cell color. The property can be chosen in the property panel of the **Cell Result** item. The mapping between cell values and color is defined by the **Legend Definition** ![](images/Legend.png) along with some appearance settings on the Legend itself. (Number format etc.) +#### TRANSXYZ +Normally the Cell Result setting gives one cell color based on the legend and the selected Result Property. This is *not* the case for the special static TRANXYZ property. This property gives each face the correct color based on the TRANS value that is associated with that particular face. + +The Positive I-face of the cell gets the cell TRANX value, while the J-face gets the TRANY-value etc. The negative faces, however, get the value from the neighbor cell in that direction. The negative I-face gets the TRANX value of the IJK-neighbor in negative I direction, and so on for the -J and -K faces. + ### Cell Edge Results ![](images/EdgeResult_1.png) The **Cell Edge Result** visualization mode is one of ResInsight's special features. Its main use is to show the MULT(X, Y, Z) properties at the same time. diff --git a/Documentation/UsersGuide/UsersGuide.md b/Documentation/UsersGuide/UsersGuide.md index 5943029015..33c21440f4 100644 --- a/Documentation/UsersGuide/UsersGuide.md +++ b/Documentation/UsersGuide/UsersGuide.md @@ -1,4 +1,4 @@ -# ![](images/AppLogo48x48.png) ResInsight 1.1 Users Guide +# ![](images/AppLogo48x48.png) ResInsight 1.2 Users Guide ## Introduction diff --git a/Fwk/AppFwk/CommonCode/cafEffectGenerator.cpp b/Fwk/AppFwk/CommonCode/cafEffectGenerator.cpp index b495d5132d..e5049e0d8d 100644 --- a/Fwk/AppFwk/CommonCode/cafEffectGenerator.cpp +++ b/Fwk/AppFwk/CommonCode/cafEffectGenerator.cpp @@ -107,7 +107,7 @@ cvf::String CommonShaderSources::light_AmbientDiffuse() //-------------------------------------------------------------------------------------------------- /// Static helper to configure polygon offset render state from enum //-------------------------------------------------------------------------------------------------- -static cvf::ref CreateAngConfigurePolygonOffsetRenderState(PolygonOffset polygonOffset) +cvf::ref EffectGenerator::createAndConfigurePolygonOffsetRenderState(PolygonOffset polygonOffset) { cvf::ref rs = new cvf::RenderStatePolygonOffset; if (polygonOffset == PO_NONE) @@ -301,7 +301,7 @@ void SurfaceEffectGenerator::updateCommonEffect(cvf::Effect* effect) const { if (m_polygonOffset != PO_NONE) { - cvf::ref polyOffset = CreateAngConfigurePolygonOffsetRenderState(m_polygonOffset); + cvf::ref polyOffset = EffectGenerator::createAndConfigurePolygonOffsetRenderState(m_polygonOffset); effect->setRenderState(polyOffset.p()); } @@ -479,7 +479,7 @@ void ScalarMapperEffectGenerator::updateCommonEffect(cvf::Effect* effect) const if (m_polygonOffset != PO_NONE) { - cvf::ref polyOffset = CreateAngConfigurePolygonOffsetRenderState(m_polygonOffset); + cvf::ref polyOffset = EffectGenerator::createAndConfigurePolygonOffsetRenderState(m_polygonOffset); effect->setRenderState(polyOffset.p()); } diff --git a/Fwk/AppFwk/CommonCode/cafEffectGenerator.h b/Fwk/AppFwk/CommonCode/cafEffectGenerator.h index a33c08412a..9d79c9d5c4 100644 --- a/Fwk/AppFwk/CommonCode/cafEffectGenerator.h +++ b/Fwk/AppFwk/CommonCode/cafEffectGenerator.h @@ -44,6 +44,7 @@ #include "cvfTextureImage.h" #include "cvfCollection.h" #include "cvfString.h" +#include "cvfRenderStatePolygonOffset.h" namespace caf { @@ -96,6 +97,8 @@ class EffectGenerator static void clearEffectCache(); static void releaseUnreferencedEffects(); + static cvf::ref createAndConfigurePolygonOffsetRenderState(caf::PolygonOffset polygonOffset); + protected: // Interface that must be implemented in base classes diff --git a/Fwk/AppFwk/cafProjectDataModel/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/CMakeLists.txt index 06cfc5c95e..24bc987236 100644 --- a/Fwk/AppFwk/cafProjectDataModel/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/CMakeLists.txt @@ -31,5 +31,6 @@ add_library( ${PROJECT_NAME} cafPdmUiOrdering.h cafPdmUiTreeOrdering.cpp cafPdmUiTreeOrdering.h - + cafPdmUiTreeEditorHandle.h + cafPdmUiTreeEditorHandle.cpp ) diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmField.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmField.h index d718abc681..d8066b7ad9 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmField.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmField.h @@ -171,7 +171,7 @@ class PdmField : public PdmFieldHandle { typedef DataType* DataTypePtr; public: - PdmField() : PdmFieldHandle() { m_fieldValue = NULL; } + PdmField() : PdmFieldHandle() { } PdmField(const PdmField& other); PdmField(const DataTypePtr& fieldValue); virtual ~PdmField(); diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmField.inl b/Fwk/AppFwk/cafProjectDataModel/cafPdmField.inl index 4d4e581a54..5d60952b13 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmField.inl +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmField.inl @@ -292,7 +292,7 @@ void caf::PdmField::readFieldData(QXmlStreamReader& xmlStream) } else { - if (dynamic_cast(obj) == NULL) + if (obj->classKeyword() != className) { assert(false); // Inconsistency in the factory. It creates objects of wrong type from the ClassKeyword @@ -341,7 +341,7 @@ void caf::PdmField::readFieldData(QXmlStreamReader& xmlStream) template void caf::PdmField::writeFieldData(QXmlStreamWriter& xmlStream) { - if (m_fieldValue == NULL) return; + if (m_fieldValue.rawPtr() == NULL) return; QString className = m_fieldValue.rawPtr()->classKeyword(); @@ -397,7 +397,7 @@ template caf::PdmField::~PdmField() { if (!m_fieldValue.isNull()) m_fieldValue.rawPtr()->removeParentField(this); - m_fieldValue = NULL; + m_fieldValue.setRawPtr(NULL); } //-------------------------------------------------------------------------------------------------- @@ -553,7 +553,6 @@ size_t PdmPointersField::count(const DataType* pointer) const template void PdmPointersField::clear() { - this->removeThisAsParentField(); m_pointers.clear(); } @@ -567,7 +566,7 @@ void PdmPointersField::deleteAllChildObjects() size_t index; for (index = 0; index < m_pointers.size(); ++index) { - delete(m_pointers[index]); + delete(m_pointers[index].rawPtr()); } m_pointers.clear(); @@ -579,7 +578,11 @@ void PdmPointersField::deleteAllChildObjects() template void PdmPointersField::erase(size_t index) { - if (m_pointers[index]) m_pointers[index]->removeParentField(this); + if (m_pointers[index]) + { + m_pointers[index]->removeParentField(this); + } + m_pointers.erase(m_pointers.begin() + index); } @@ -589,21 +592,23 @@ void PdmPointersField::erase(size_t index) template void PdmPointersField::removeChildObject(PdmObject* object) { - DataType* pointer = dynamic_cast(object); - - size_t index; std::vector< PdmPointer > tempPointers; + tempPointers = m_pointers; m_pointers.clear(); - for (index = 0; index < tempPointers.size(); ++index) + + for (size_t index = 0; index < tempPointers.size(); ++index) { - if (tempPointers[index] != pointer) + if (tempPointers[index].rawPtr() != object) { m_pointers.push_back(tempPointers[index]); } else { - if (tempPointers[index]) tempPointers[index]->removeParentField(this); + if (tempPointers[index].rawPtr()) + { + tempPointers[index].rawPtr()->removeParentField(this); + } } } } @@ -618,12 +623,12 @@ template typename std::vector< PdmPointer >::iterator it; for (it = m_pointers.begin(); it != m_pointers.end(); ++it) { - if (*it == NULL) continue; + if (it->rawPtr() == NULL) continue; - QString className = (*it)->classKeyword(); + QString className = it->rawPtr()->classKeyword(); xmlStream.writeStartElement("", className); - (*it)->writeFields(xmlStream); + it->rawPtr()->writeFields(xmlStream); xmlStream.writeEndElement(); } } @@ -661,9 +666,7 @@ template continue; } - currentObject = dynamic_cast (obj); - - if (currentObject == NULL) + if (obj->classKeyword() != className) { assert(false); // There is an inconsistency in the factory. It creates objects of type not matching the ClassKeyword @@ -678,8 +681,11 @@ template continue; } - currentObject->readFields(xmlStream); - this->push_back(currentObject); + obj->readFields(xmlStream); + + m_pointers.push_back(PdmPointer()); + m_pointers.back().setRawPtr(obj); + obj->addParentField(this); // Jump off the end element, and head for next start element (or the final EndElement of the field) // Qt reports a character token between EndElements and StartElements so skip it @@ -700,7 +706,7 @@ void PdmPointersField::childObjects(std::vector* objects) size_t i; for (i = 0; i < m_pointers.size(); ++i) { - objects->push_back(m_pointers[i]); + objects->push_back(m_pointers[i].rawPtr()); } } @@ -715,7 +721,7 @@ void PdmPointersField::removeThisAsParentField() { if (!it->isNull()) { - (*it)->removeParentField(this); + it->rawPtr()->removeParentField(this); } } } diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmObject.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmObject.cpp index 9f6acd1a49..d752765d8e 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmObject.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmObject.cpp @@ -421,7 +421,7 @@ PdmUiTreeOrdering* PdmObject::uiTreeOrdering(QString uiConfigName /*= ""*/) } } - expandUiTree(uiTreeOrdering, uiConfigName); + addUiTreeChildren(uiTreeOrdering, uiConfigName); return uiTreeOrdering; } @@ -429,13 +429,13 @@ PdmUiTreeOrdering* PdmObject::uiTreeOrdering(QString uiConfigName /*= ""*/) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void PdmObject::expandUiTree(PdmUiTreeOrdering* root, QString uiConfigName /*= "" */) +void PdmObject::addUiTreeChildren(PdmUiTreeOrdering* root, QString uiConfigName /*= "" */) { if (!root) return; - if ( root->childCount() == 0) + if ( root->childCount() == 0) // This means that no one has tried to expand it. { - if (!root->isSubTreeDefined() && root->dataObject()) + if (!root->ignoreSubTree() && root->dataObject()) { if (root->m_field && !root->m_field->isUiChildrenHidden(uiConfigName)) @@ -449,7 +449,7 @@ void PdmObject::expandUiTree(PdmUiTreeOrdering* root, QString uiConfigName /*= " } else { - root->dataObject()->defineUiTreeOrdering(*root, uiConfigName); + root->object()->defineUiTreeOrdering(*root, uiConfigName); } } } @@ -457,9 +457,9 @@ void PdmObject::expandUiTree(PdmUiTreeOrdering* root, QString uiConfigName /*= " for (int cIdx = 0; cIdx < root->childCount(); ++cIdx) { PdmUiTreeOrdering* child = dynamic_cast(root->child(cIdx)); - if (!child->isSubTreeDefined()) + if (!child->ignoreSubTree()) { - expandUiTree(child); + addUiTreeChildren(child); } } } diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmObject.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmObject.h index 75fd509b53..94eb759c48 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmObject.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmObject.h @@ -255,7 +255,7 @@ class PdmObject : public PdmUiItem private: /// Recursive function to traverse and create a Ui tree representation of the object hierarchy - static void expandUiTree( PdmUiTreeOrdering* root, QString uiConfigName = "" ); + static void addUiTreeChildren( PdmUiTreeOrdering* root, QString uiConfigName = "" ); private: std::multiset m_parentFields; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiObjectEditorHandle.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiObjectEditorHandle.cpp index f5b845ab81..be166acb83 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiObjectEditorHandle.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiObjectEditorHandle.cpp @@ -59,6 +59,8 @@ QWidget* PdmUiObjectEditorHandle::getOrCreateWidget(QWidget* parent) //-------------------------------------------------------------------------------------------------- void PdmUiObjectEditorHandle::setPdmObject(PdmObject* object) { + cleanupBeforeSettingPdmObject(); + this->bindToPdmItem(object); } diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiObjectEditorHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiObjectEditorHandle.h index 45138b2f35..f7bcb41bfd 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiObjectEditorHandle.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiObjectEditorHandle.h @@ -66,6 +66,7 @@ class PdmUiObjectEditorHandle: public PdmUiEditorHandle protected: virtual QWidget* createWidget(QWidget* parent) = 0; + virtual void cleanupBeforeSettingPdmObject() {}; protected: QPointer m_widget; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiTreeEditorHandle.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiTreeEditorHandle.cpp new file mode 100644 index 0000000000..943a9a0fbe --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiTreeEditorHandle.cpp @@ -0,0 +1,76 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2013 Ceetron AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + +#include "cafPdmUiTreeEditorHandle.h" +#include "cafPdmObject.h" + +namespace caf +{ + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QWidget* PdmUiTreeEditorHandle::getOrCreateWidget(QWidget* parent) +{ + if (m_widget.isNull()) + { + m_widget = this->createWidget(parent); + } + return m_widget; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiTreeEditorHandle::setPdmItemRoot(PdmUiItem* root) +{ + cleanupBeforeSettingPdmObject(); + + this->bindToPdmItem(root); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiItem* PdmUiTreeEditorHandle::pdmItemRoot() +{ + return this->pdmItem(); +} + +} //End of namespace caf + diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiTreeEditorHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiTreeEditorHandle.h new file mode 100644 index 0000000000..e96a59c6b9 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiTreeEditorHandle.h @@ -0,0 +1,78 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2013 Ceetron AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + +#pragma once +#include +#include +#include +#include +#include "cafPdmUiEditorHandle.h" +#include "cafPdmPointer.h" + +namespace caf +{ + +class PdmObject; + +//================================================================================================== +/// Abstract class to handle editors for complete PdmObjects +//================================================================================================== + +class PdmUiTreeEditorHandle: public PdmUiEditorHandle +{ +public: + PdmUiTreeEditorHandle() {} + ~PdmUiTreeEditorHandle() {} + + QWidget* getOrCreateWidget(QWidget* parent); + QWidget* widget() { return m_widget; } + + void setPdmItemRoot(PdmUiItem* root); + PdmUiItem* pdmItemRoot(); + +protected: + virtual QWidget* createWidget(QWidget* parent) = 0; + virtual void cleanupBeforeSettingPdmObject() {}; + +protected: + QPointer m_widget; +}; + + + +} // End of namespace caf + diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiTreeOrdering.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiTreeOrdering.cpp index 9135a6c07d..bea9b8a19a 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiTreeOrdering.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiTreeOrdering.cpp @@ -65,7 +65,11 @@ namespace caf PdmUiTreeOrdering* PdmUiTreeOrdering::add(const QString & title, const QString& iconResourceName) { PdmUiTreeOrdering* to = new PdmUiTreeOrdering(this, -1, NULL); - to->m_uiInfo = new PdmUiItemInfo(title, QIcon(iconResourceName)); + + to->m_uiItem = new PdmUiItem(); + to->m_uiItem->setUiName(title); + to->m_uiItem->setUiIcon(QIcon(iconResourceName)); + return to; } @@ -98,7 +102,7 @@ namespace caf { PdmUiTreeOrdering* child = dynamic_cast(this->child(cIdx)); - if (child->dataObject() == object) + if (child->object() == object) { return true; } @@ -112,15 +116,27 @@ namespace caf /// Creates an new PdmUiTreeOrdering item, and adds it to parent. If position is -1, it is added /// at the end of parents existing child list. //-------------------------------------------------------------------------------------------------- - PdmUiTreeOrdering::PdmUiTreeOrdering(PdmUiTreeOrdering* parent /*= NULL*/, int position /*= -1*/, PdmObject* dataObject /*= NULL*/) : UiTreeItem< PdmPointer >(parent, position, dataObject), + PdmUiTreeOrdering::PdmUiTreeOrdering(PdmUiTreeOrdering* parent /*= NULL*/, int position /*= -1*/, PdmObject* dataObject /*= NULL*/) : PdmUiTreeItem(parent, position, this), m_field(NULL), - m_uiInfo(NULL), m_forgetRemainingFields(false), - m_isSubTreeDefined(false) + m_isToIgnoreSubTree(false), + m_uiItem(NULL), + m_object(dataObject) { } + //-------------------------------------------------------------------------------------------------- + /// + //-------------------------------------------------------------------------------------------------- + PdmUiTreeOrdering::~PdmUiTreeOrdering() + { + if (m_uiItem) + { + delete m_uiItem; + } + } + } //End of namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiTreeOrdering.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiTreeOrdering.h index 5d9def89b4..e43b74191d 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiTreeOrdering.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiTreeOrdering.h @@ -49,16 +49,19 @@ namespace caf class PdmObject; class PdmFieldHandle; -//typedef UiTreeItem > PdmUiTreeItem; +class PdmUiTreeOrdering; + +typedef UiTreeItem PdmUiTreeItem; //================================================================================================== /// Class storing a tree structure representation of some PdmObject hierarchy to be used for tree views in the Gui //================================================================================================== -class PdmUiTreeOrdering : public UiTreeItem< PdmPointer > +class PdmUiTreeOrdering : public UiTreeItem< PdmUiTreeOrdering* > { public: PdmUiTreeOrdering(PdmUiTreeOrdering* parent = NULL, int position = -1, PdmObject* dataObject = NULL); + ~PdmUiTreeOrdering(); void add(PdmFieldHandle * field); void add(PdmObject* object); @@ -67,23 +70,26 @@ class PdmUiTreeOrdering : public UiTreeItem< PdmPointer > /// If the rest of the fields containing children is supposed to be omitted, setForgetRemainingFileds to true. void setForgetRemainingFields(bool val) { m_forgetRemainingFields = val; } /// To stop the tree generation at this level, setSubTreeDefined to true - void setSubTreeDefined(bool isSubTreeDefined ) { m_isSubTreeDefined = isSubTreeDefined; } + void setIgnoreSubTree(bool doIgnoreSubTree ) { m_isToIgnoreSubTree = doIgnoreSubTree; } + PdmObject* object() const { return m_object; } PdmFieldHandle* field() const { return m_field; } + PdmUiItem* uiItem() const { return m_uiItem; } private: friend class PdmObject; bool forgetRemainingFields() const { return m_forgetRemainingFields; } - bool isSubTreeDefined() const { return m_isSubTreeDefined; } + bool ignoreSubTree() const { return m_isToIgnoreSubTree; } bool containsField(const PdmFieldHandle* field); bool containsObject(const PdmObject* object); private: + PdmPointer m_object; PdmFieldHandle* m_field; - PdmUiItemInfo* m_uiInfo; + PdmUiItem* m_uiItem; bool m_forgetRemainingFields; - bool m_isSubTreeDefined; + bool m_isToIgnoreSubTree; }; diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/CMakeLists.txt b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/CMakeLists.txt index 2835458d37..2f531891ab 100644 --- a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/CMakeLists.txt +++ b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/CMakeLists.txt @@ -14,6 +14,9 @@ include_directories ( add_executable (${PROJECT_NAME} cafPdmBasicTest.cpp cafProjectDataModel_UnitTests.cpp + Child.cpp + Parent.cpp + TestObj.cpp ${CMAKE_SOURCE_DIR}/cafTests/gtest/gtest-all.cpp ) diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Child.cpp b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Child.cpp new file mode 100644 index 0000000000..74adee05b3 --- /dev/null +++ b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Child.cpp @@ -0,0 +1,13 @@ +#include "Child.h" +#include "TestObj.h" + +CAF_PDM_SOURCE_INIT(Child, "Child"); + +Child::Child() +{ + CAF_PDM_InitFieldNoDefault(&m_testObj, "Numbers", "Important Numbers", "", "", ""); +} + +Child::~Child() +{ +} diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Child.h b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Child.h new file mode 100644 index 0000000000..82e91dfd4f --- /dev/null +++ b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Child.h @@ -0,0 +1,22 @@ +#pragma once + +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" + +class TestObj; + +class Child: public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + Child(); + + ~Child(); + + + caf::PdmField m_testObj; +}; + + diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Parent.cpp b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Parent.cpp new file mode 100644 index 0000000000..26d3f4fd01 --- /dev/null +++ b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Parent.cpp @@ -0,0 +1,32 @@ +#include "Parent.h" +//#include "Child.h" + +CAF_PDM_SOURCE_INIT(Parent, "Parent"); + + +Parent::Parent() +{ + CAF_PDM_InitFieldNoDefault(&m_simpleObjectsField, "SimpleObjects", "A child object", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_simpleObjectF, "SimpleObject", "A child object", "", "", ""); +} + +Parent::~Parent() +{ +} + + void Parent::doSome() +{ + size_t i = m_simpleObjectsField.size(); + if (i){ + //Child* c = m_simpleObjectsField[0]; + //TestObj* to = c->m_testObj(); + } +} + +#include + + TEST(IncludeTest, Basic) + { + Parent* p = new Parent; + delete(p); + } diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Parent.h b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Parent.h new file mode 100644 index 0000000000..bb4ec86f43 --- /dev/null +++ b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Parent.h @@ -0,0 +1,52 @@ +#pragma once + +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" + +#if 0 +class PdmPointerTarget +{ +public: + PdmPointerTarget() {} + PdmPointerTarget(const PdmPointerTarget& ) {} + PdmPointerTarget& operator=(const PdmPointerTarget& ) {} + + virtual ~PdmPointerTarget() + { + // Set all guarded pointers pointing to this to NULL + + std::set::iterator it; + for (it = m_pointersReferencingMe.begin(); it != m_pointersReferencingMe.end() ; ++it) + { + (**it) = NULL; + } + } + +private: + + // Support system for PdmPointer + + friend class PdmPointerImpl; + std::set m_pointersReferencingMe; +}; + +#endif + +class Child; + + +class Parent: public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + + +public: + Parent(); + ~Parent(); + + void doSome(); + + caf::PdmPointersField m_simpleObjectsField; + caf::PdmField m_simpleObjectF; +}; diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/TestObj.cpp b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/TestObj.cpp new file mode 100644 index 0000000000..ec07283fb7 --- /dev/null +++ b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/TestObj.cpp @@ -0,0 +1,11 @@ +#include "TestObj.h" + +CAF_PDM_SOURCE_INIT(TestObj, "TestObj"); + +TestObj::TestObj() +{ + CAF_PDM_InitObject("TestObj", "", "", ""); + CAF_PDM_InitField(&m_position, "Position", 8765.2, "Position", "", "", ""); +} + +TestObj::~TestObj() {} diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/TestObj.h b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/TestObj.h new file mode 100644 index 0000000000..b5a33112ea --- /dev/null +++ b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/TestObj.h @@ -0,0 +1,18 @@ +#pragma once + +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" + +class TestObj: public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + + +public: + TestObj(); + + ~TestObj(); + + caf::PdmField m_position; +}; diff --git a/Fwk/AppFwk/cafUserInterface/CMakeLists.txt b/Fwk/AppFwk/cafUserInterface/CMakeLists.txt index 9db951500d..b210e4a322 100644 --- a/Fwk/AppFwk/cafUserInterface/CMakeLists.txt +++ b/Fwk/AppFwk/cafUserInterface/CMakeLists.txt @@ -11,6 +11,7 @@ set( QOBJECT_HEADERS cafUiTreeModelPdm.h cafUiProcess.h + cafPdmSettings.h cafPdmUiLineEditor.h cafPdmUiCheckBoxEditor.h cafPdmUiComboBoxEditor.h @@ -24,7 +25,9 @@ set( QOBJECT_HEADERS cafPdmUiColorEditor.h cafPdmUiPropertyView.h + cafPdmUiPropertyDialog.h cafPdmUiTreeView.h + cafPdmUiTreeViewModel.h cafPdmUiListView.h cafPdmUiListViewEditor.h ) @@ -37,6 +40,7 @@ endif() add_library( ${PROJECT_NAME} cafAboutDialog.cpp cafAboutDialog.h + cafPdmSettings.cpp cafPdmUiCheckBoxEditor.cpp cafPdmUiCheckBoxEditor.h cafPdmUiColorEditor.cpp @@ -56,6 +60,8 @@ add_library( ${PROJECT_NAME} cafPdmUiListViewEditor.cpp cafPdmUiListViewEditor.h cafPdmUiListView.cpp + cafPdmUiPropertyDialog.cpp + cafPdmUiPropertyDialog.h cafPdmUiPropertyView.cpp cafPdmUiPropertyView.h cafPdmUiPushButtonEditor.cpp @@ -66,6 +72,8 @@ add_library( ${PROJECT_NAME} cafPdmUiTextEditor.h cafPdmUiTreeViewEditor.cpp cafPdmUiTreeViewEditor.h + cafPdmUiTreeViewModel.cpp + cafPdmUiTreeViewModel.h cafPdmUiTreeView.cpp cafProgressInfo.cpp cafProgressInfo.h diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmSettings.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmSettings.cpp new file mode 100644 index 0000000000..a8e3a3ba5c --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPdmSettings.cpp @@ -0,0 +1,116 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2013 Ceetron AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + +#include "cafPdmSettings.h" +#include "cafPdmField.h" + +#include + + +namespace caf +{ + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Settings::readFieldsFromApplicationStore(caf::PdmObject* object) +{ + // Qt doc : + // + // Constructs a QSettings object for accessing settings of the application and organization + // set previously with a call to QCoreApplication::setOrganizationName(), + // QCoreApplication::setOrganizationDomain(), and QCoreApplication::setApplicationName(). + QSettings settings; + + QString prefix = object->classKeyword(); + if (!prefix.isEmpty()) + { + prefix += "/"; + } + + std::vector fields; + object->fields(fields); + size_t i; + for (i = 0; i < fields.size(); i++) + { + caf::PdmFieldHandle* fieldHandle = fields[i]; + + QString keywordWithPrefix = prefix + fieldHandle->keyword(); + if (settings.contains(keywordWithPrefix)) + { + QVariant val = settings.value(keywordWithPrefix); + fieldHandle->setValueFromUi(val); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Settings::writeFieldsToApplicationStore(caf::PdmObject* object) +{ + assert(object); + + // Qt doc : + // + // Constructs a QSettings object for accessing settings of the application and organization + // set previously with a call to QCoreApplication::setOrganizationName(), + // QCoreApplication::setOrganizationDomain(), and QCoreApplication::setApplicationName(). + QSettings settings; + + QString prefix = object->classKeyword(); + if (!prefix.isEmpty()) + { + prefix += "/"; + } + + std::vector fields; + object->fields(fields); + + size_t i; + for (i = 0; i < fields.size(); i++) + { + caf::PdmFieldHandle* fieldHandle = fields[i]; + + QString keywordWithPrefix = prefix + fieldHandle->keyword(); + settings.setValue(keywordWithPrefix, fieldHandle->uiValue()); + } +} + + +} // namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmSettings.h b/Fwk/AppFwk/cafUserInterface/cafPdmSettings.h new file mode 100644 index 0000000000..2342eacd71 --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPdmSettings.h @@ -0,0 +1,55 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2013 Ceetron AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + +#pragma once + +#include + +namespace caf +{ + + class PdmObject; + +class Settings +{ +public: + static void readFieldsFromApplicationStore(caf::PdmObject* object); + static void writeFieldsToApplicationStore(caf::PdmObject* object); +}; + + +} // end namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiDefaultObjectEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiDefaultObjectEditor.cpp index 822d2c3185..5bfee7de4f 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiDefaultObjectEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiDefaultObjectEditor.cpp @@ -65,10 +65,11 @@ CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR(PdmUiLineEditor, QString); CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR(PdmUiLineEditor, int); CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR(PdmUiLineEditor, double); CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR(PdmUiLineEditor, float); +CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR(PdmUiLineEditor, quint64); + CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR(PdmUiListEditor, std::vector); CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR(PdmUiListEditor, std::vector); CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR(PdmUiListEditor, std::vector); - CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR(PdmUiListEditor, std::vector); diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiPropertyDialog.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiPropertyDialog.cpp new file mode 100644 index 0000000000..277dc3153d --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiPropertyDialog.cpp @@ -0,0 +1,92 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2013 Ceetron AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + +#include "cafPdmUiPropertyDialog.h" + +#include "cafPdmObject.h" +#include "cafPdmUiPropertyView.h" + +#include +#include + +#include + + + +namespace caf { + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiPropertyDialog::PdmUiPropertyDialog(QWidget* parent, caf::PdmObject* object, const QString& windowTitle) + : QDialog(parent) +{ + assert(object); + + m_pdmObject = object; + m_windowTitle = windowTitle; + + setupUi(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiPropertyDialog::setupUi() +{ + setWindowTitle(m_windowTitle); + + m_pdmUiPropertyView = new caf::PdmUiPropertyView(this); + + QVBoxLayout* dialogLayout = new QVBoxLayout; + setLayout(dialogLayout); + + dialogLayout->addWidget(m_pdmUiPropertyView); + m_pdmUiPropertyView->showProperties(m_pdmObject); + + // Buttons + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + dialogLayout->addWidget(buttonBox); + + this->resize(400, 200); +} + + +} // end namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiPropertyDialog.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiPropertyDialog.h new file mode 100644 index 0000000000..4c4ca7b797 --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiPropertyDialog.h @@ -0,0 +1,70 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2013 Ceetron AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + +#pragma once + +#include + +namespace caf +{ + class PdmObject; + class PdmUiPropertyView; + + +//================================================================================================== +// +// +// +//================================================================================================== +class PdmUiPropertyDialog : public QDialog +{ + Q_OBJECT + +public: + PdmUiPropertyDialog(QWidget* parent, caf::PdmObject* object, const QString& windowTitle); + +private: + void setupUi(); + +private: + QString m_windowTitle; + caf::PdmObject* m_pdmObject; + caf::PdmUiPropertyView* m_pdmUiPropertyView; +}; + + +} // end namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeViewModel.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeViewModel.cpp new file mode 100644 index 0000000000..223c98d105 --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeViewModel.cpp @@ -0,0 +1,567 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2014 Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + +#include "cafPdmUiTreeViewModel.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmUiTreeOrdering.h" + + + +namespace caf +{ + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiTreeViewModel::PdmUiTreeViewModel(QObject* parent) +{ + m_treeItemRoot = NULL; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiTreeViewModel::setTreeItemRoot(PdmUiTreeItem* root) +{ + beginResetModel(); + + if (m_treeItemRoot) + { + delete m_treeItemRoot; + } + + m_treeItemRoot = root; + endResetModel(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QModelIndex PdmUiTreeViewModel::index(int row, int column, const QModelIndex &parentIndex /*= QModelIndex( ) */) const +{ +// if (!m_treeItemRoot) +// return QModelIndex(); + + if (!hasIndex(row, column, parentIndex)) + return QModelIndex(); + + PdmUiTreeItem* parentItem = NULL; + + if (!parentIndex.isValid()) + parentItem = m_treeItemRoot; + else + parentItem = static_cast(parentIndex.internalPointer()); + + PdmUiTreeItem* childItem = parentItem->child(row); + if (childItem) + return createIndex(row, column, childItem); + else + return QModelIndex(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QModelIndex PdmUiTreeViewModel::parent(const QModelIndex &childIndex) const +{ +// if (!m_treeItemRoot) return QModelIndex(); + + if (!childIndex.isValid()) return QModelIndex(); + + PdmUiTreeItem* childItem = static_cast(childIndex.internalPointer()); + if (!childItem) return QModelIndex(); + + PdmUiTreeItem* parentItem = childItem->parent(); + if (!parentItem) return QModelIndex(); + + if (parentItem == m_treeItemRoot) return QModelIndex(); + + return createIndex(parentItem->row(), 0, parentItem); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int PdmUiTreeViewModel::rowCount(const QModelIndex &parentIndex /*= QModelIndex( ) */) const +{ + if (!m_treeItemRoot) + return 0; + + if (parentIndex.column() > 0) + return 0; + + PdmUiTreeItem* parentItem; + if (!parentIndex.isValid()) + parentItem = m_treeItemRoot; + else + parentItem = PdmUiTreeViewModel::getTreeItemFromIndex(parentIndex); + + return parentItem->childCount(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int PdmUiTreeViewModel::columnCount(const QModelIndex &parentIndex /*= QModelIndex( ) */) const +{ + if (!m_treeItemRoot) + return 0; + + if (parentIndex.isValid()) + { + PdmUiTreeItem* parentItem = PdmUiTreeViewModel::getTreeItemFromIndex(parentIndex); + if (parentItem) + { + return parentItem->columnCount(); + } + else + { + return 0; + } + } + else + return m_treeItemRoot->columnCount(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QVariant PdmUiTreeViewModel::data(const QModelIndex &index, int role /*= Qt::DisplayRole */) const +{ + if (!index.isValid()) + return QVariant(); + + PdmUiTreeOrdering* uitreeOrdering = static_cast(index.internalPointer()); + if (!uitreeOrdering) + { + return QVariant(); + } + PdmFieldHandle* pdmField = uitreeOrdering->field(); + PdmObject* pdmObj = uitreeOrdering->object(); + + if (role == Qt::DisplayRole || role == Qt::EditRole) + { + if (pdmField && !pdmField->uiName().isEmpty()) + { + return pdmField->uiName(); + } + else if (pdmObj) + { + if (pdmObj->userDescriptionField()) + return pdmObj->userDescriptionField()->uiValue(); + else + return pdmObj->uiName(); + } + else if (uitreeOrdering->uiItem()) + { + return uitreeOrdering->uiItem()->uiName(); + } + else + { + // Should not get here + assert(0); + } + } + else if (role == Qt::DecorationRole) + { + if (pdmField && !pdmField->uiIcon().isNull()) + { + return pdmField->uiIcon(); + } + else if (pdmObj) + { + return pdmObj->uiIcon(); + } + else if (uitreeOrdering->uiItem()) + { + return uitreeOrdering->uiItem()->uiIcon(); + } + else + { + // Should not get here + assert(0); + } + } + else if (role == Qt::ToolTipRole) + { + if (pdmField && !pdmField->uiToolTip().isEmpty()) + return pdmField->uiToolTip(); + else if (pdmObj) + { + return pdmObj->uiToolTip(); + } + else if (uitreeOrdering->uiItem()) + { + return uitreeOrdering->uiItem()->uiToolTip(); + } + else + { + // Should not get here + assert(0); + } + } + else if (role == Qt::WhatsThisRole) + { + if (pdmField && !pdmField->uiWhatsThis().isEmpty()) + return pdmField->uiWhatsThis(); + else if (pdmObj) + { + return pdmObj->uiWhatsThis(); + } + else if (uitreeOrdering->uiItem()) + { + return uitreeOrdering->uiItem()->uiWhatsThis(); + } + else + { + // Should not get here + assert(0); + } + } + else if (role == Qt::CheckStateRole) + { + if (pdmObj && pdmObj->objectToggleField()) + { + bool isToggledOn = pdmObj->objectToggleField()->uiValue().toBool(); + if (isToggledOn) + { + return Qt::Checked; + } + else + { + return Qt::Unchecked; + } + } + } + + return QVariant(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiTreeViewModel::emitDataChanged(const QModelIndex& index) +{ + emit dataChanged(index, index); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool PdmUiTreeViewModel::setData(const QModelIndex &index, const QVariant &value, int role /*= Qt::EditRole*/) +{ + if (!index.isValid()) + { + return false; + } + + PdmUiTreeItem* treeItem = PdmUiTreeViewModel::getTreeItemFromIndex(index); + assert(treeItem); + + PdmObject* obj = treeItem->dataObject()->object(); + if (!obj) + { + return false; + } + + if (role == Qt::EditRole && obj->userDescriptionField()) + { + obj->userDescriptionField()->setValueFromUi(value); + + emitDataChanged(index); + + return true; + } + else if (role == Qt::CheckStateRole && obj->objectToggleField()) + { + bool toggleOn = (value == Qt::Checked); + + obj->objectToggleField()->setValueFromUi(toggleOn); + + emitDataChanged(index); + + return true; + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// Enable edit of this item if we have a editable user description field for a pdmObject +/// Disable edit for other items +//-------------------------------------------------------------------------------------------------- +Qt::ItemFlags PdmUiTreeViewModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::ItemIsEnabled; + + Qt::ItemFlags flagMask = QAbstractItemModel::flags(index); + + PdmUiTreeItem* treeItem = getTreeItemFromIndex(index); + if (treeItem) + { + PdmObject* pdmObject = treeItem->dataObject()->object(); + if (pdmObject) + { + if (pdmObject->userDescriptionField() && !pdmObject->userDescriptionField()->isUiReadOnly()) + { + flagMask = flagMask | Qt::ItemIsEditable; + } + + if (pdmObject->objectToggleField()) + { + flagMask = flagMask | Qt::ItemIsUserCheckable; + } + + if (pdmObject->isUiReadOnly()) + { + flagMask = flagMask & (~Qt::ItemIsEnabled); + } + + } + } + else + { + flagMask = flagMask & (~Qt::ItemIsEditable); + } + + return flagMask; +} + + +//-------------------------------------------------------------------------------------------------- +/// Refreshes the UI-tree below the supplied root PdmObject +//-------------------------------------------------------------------------------------------------- +void PdmUiTreeViewModel::updateUiSubTree(PdmObject* pdmRoot) +{ + // Build the new "Correct" Tree + + PdmUiTreeOrdering* tempUpdatedPdmTree = pdmRoot->uiTreeOrdering(); + + // Find the corresponding entry for "root" in the existing Ui tree + + QModelIndex uiSubTreeRootModelIdx = getModelIndexFromPdmObject(pdmRoot); + + PdmUiTreeItem* uiModelSubTreeRoot = NULL; + if (uiSubTreeRootModelIdx.isValid()) + { + uiModelSubTreeRoot = getTreeItemFromIndex(uiSubTreeRootModelIdx); + } + else + { + uiModelSubTreeRoot = m_treeItemRoot; + } + + + updateModelSubTree(uiSubTreeRootModelIdx, uiModelSubTreeRoot, tempUpdatedPdmTree); + + delete tempUpdatedPdmTree; +} + +//-------------------------------------------------------------------------------------------------- +/// Makes the destinationSubTreeRoot tree become identical to the tree in sourceSubTreeRoot, +/// calling begin..() end..() to make the UI update accordingly. +/// This assumes that all the items have a pointer an unique PdmObject +//-------------------------------------------------------------------------------------------------- +void PdmUiTreeViewModel::updateModelSubTree(const QModelIndex& modelIdxOfDestinationSubTreeRoot, PdmUiTreeItem* destinationSubTreeRoot, PdmUiTreeItem* sourceSubTreeRoot) +{ + // First loop over children in the old ui tree, deleting the ones not present in + // the newUiTree + + for (int resultChildIdx = 0; resultChildIdx < destinationSubTreeRoot->childCount() ; ++resultChildIdx) + { + PdmUiTreeItem* oldChild = destinationSubTreeRoot->child(resultChildIdx); + int childIndex = sourceSubTreeRoot->findChildItemIndex(oldChild->dataObject()); + + if (childIndex == -1) // Not found + { + this->beginRemoveRows(modelIdxOfDestinationSubTreeRoot, resultChildIdx, resultChildIdx); + destinationSubTreeRoot->removeChildren(resultChildIdx, 1); + this->endRemoveRows(); + resultChildIdx--; + } + } + + // Then loop over the children in the new ui tree, finding the corresponding items in the old tree. + // If they are found, we move them to the correct position. + // If not found, we pulls the item out of the old ui tree, inserting it into the new tree to avoid the default delete operation in ~UiTreeItem() + + int sourceChildCount = sourceSubTreeRoot->childCount(); + int sourceChildIdx = 0; + + for (int resultChildIdx = 0; resultChildIdx < sourceChildCount; ++resultChildIdx, ++sourceChildIdx) + { + PdmUiTreeItem* newChild = sourceSubTreeRoot->child(sourceChildIdx); + int childIndex = destinationSubTreeRoot->findChildItemIndex(newChild->dataObject()); + + if (childIndex == -1) // Not found + { + this->beginInsertRows(modelIdxOfDestinationSubTreeRoot, resultChildIdx, resultChildIdx); + destinationSubTreeRoot->insertChild(resultChildIdx, newChild); + this->endInsertRows(); + sourceSubTreeRoot->removeChildrenNoDelete(sourceChildIdx, 1); + sourceChildIdx--; + } + else if (childIndex != resultChildIdx) // Found, but must be moved + { + assert(childIndex > resultChildIdx); + + PdmUiTreeItem* oldChild = destinationSubTreeRoot->child(childIndex); + this->beginMoveRows(modelIdxOfDestinationSubTreeRoot, childIndex, childIndex, modelIdxOfDestinationSubTreeRoot, resultChildIdx); + destinationSubTreeRoot->removeChildrenNoDelete(childIndex, 1); + destinationSubTreeRoot->insertChild(resultChildIdx, oldChild); + this->endMoveRows(); + updateModelSubTree( index(resultChildIdx, 0, modelIdxOfDestinationSubTreeRoot), oldChild, newChild); + } + else // Found the corresponding item in the right place. + { + PdmUiTreeItem* oldChild = destinationSubTreeRoot->child(childIndex); + updateModelSubTree( index(resultChildIdx, 0, modelIdxOfDestinationSubTreeRoot), oldChild, newChild); + } + } + + +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiTreeItem* PdmUiTreeViewModel::treeItemRoot() +{ + return m_treeItemRoot; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiTreeViewModel::notifyModelChanged() +{ + QModelIndex startModelIdx = index(0,0); + QModelIndex endModelIdx = index(rowCount(startModelIdx), 0); + + emit dataChanged(startModelIdx, endModelIdx); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QVariant PdmUiTreeViewModel::headerData(int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole */) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (section < m_columnHeaders.size()) + { + return m_columnHeaders[section]; + } + + return QVariant(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiTreeViewModel::setColumnHeaders(const QStringList& columnHeaders) +{ + m_columnHeaders = columnHeaders; +} + + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiTreeItem* caf::PdmUiTreeViewModel::getTreeItemFromIndex(const QModelIndex& index) +{ + if (index.isValid()) + { + assert(index.internalPointer()); + + PdmUiTreeItem* treeItem = static_cast(index.internalPointer()); + return treeItem; + } + + return NULL; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QModelIndex caf::PdmUiTreeViewModel::getModelIndexFromPdmObjectRecursive(const QModelIndex& currentIndex, const PdmObject * object) const +{ + if (currentIndex.internalPointer()) + { + PdmUiTreeItem* treeItem = static_cast(currentIndex.internalPointer()); + if (treeItem->dataObject()->object() == object) return currentIndex; + } + + int row; + for (row = 0; row < rowCount(currentIndex); ++row) + { + QModelIndex foundIndex = getModelIndexFromPdmObjectRecursive(index(row, 0, currentIndex), object); + if (foundIndex.isValid()) return foundIndex; + } + return QModelIndex(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QModelIndex caf::PdmUiTreeViewModel::getModelIndexFromPdmObject( const PdmObject * object) const +{ + QModelIndex foundIndex; + int numRows = rowCount(QModelIndex()); + int r = 0; + while (r < numRows && !foundIndex.isValid()) + { + foundIndex = getModelIndexFromPdmObjectRecursive(index(r, 0, QModelIndex()), object); + ++r; + } + return foundIndex; +} + + + + + + +} // end namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeViewModel.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeViewModel.h new file mode 100644 index 0000000000..c8a1028be6 --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeViewModel.h @@ -0,0 +1,114 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2014 Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + +#pragma once + +#include "cafUiTreeItem.h" + +#include +#include + +#include +#include "cafPdmPointer.h" + + +namespace caf +{ + +class PdmObject; + +//typedef UiTreeItem > PdmUiTreeItem; +class PdmUiTreeOrdering; +typedef UiTreeItem PdmUiTreeItem; +//================================================================================================== +// +// This class is intended to replace UiTreeModelPdm (cafUiTreeModelPdm) +// +//================================================================================================== +class PdmUiTreeViewModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + PdmUiTreeViewModel(QObject* parent); + + void setTreeItemRoot(PdmUiTreeItem* root); + PdmUiTreeItem* treeItemRoot(); + + void emitDataChanged(const QModelIndex& index); + + static PdmUiTreeItem* getTreeItemFromIndex(const QModelIndex& index); + QModelIndex getModelIndexFromPdmObject(const PdmObject* object) const; + void updateUiSubTree(PdmObject* root); + + void notifyModelChanged(); + void setColumnHeaders(const QStringList& columnHeaders); + +public: + // Overrides from QAbstractItemModel + virtual QModelIndex index(int row, int column, const QModelIndex &parentIndex = QModelIndex( )) const; + virtual QModelIndex parent(const QModelIndex &index) const; + virtual int rowCount(const QModelIndex &parentIndex = QModelIndex( ) ) const; + virtual int columnCount(const QModelIndex &parentIndex = QModelIndex( ) ) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole ) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; + + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + +protected: + QModelIndex getModelIndexFromPdmObjectRecursive(const QModelIndex& currentIndex, const PdmObject * object) const; +private: + void updateModelSubTree(const QModelIndex& uiSubTreeRootModelIdx, PdmUiTreeItem* uiModelSubTreeRoot, PdmUiTreeItem* updatedPdmSubTreeRoot); + + PdmUiTreeItem* m_treeItemRoot; + QStringList m_columnHeaders; +}; + + + +//================================================================================================== +/// +//================================================================================================== +class UiTreeItemBuilderPdm +{ +public: + static PdmUiTreeItem* buildViewItems(PdmUiTreeItem* parentTreeItem, int position, caf::PdmObject* object); +}; + +} // End of namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafProgressInfo.cpp b/Fwk/AppFwk/cafUserInterface/cafProgressInfo.cpp index 03847fdc3b..94abc195ba 100644 --- a/Fwk/AppFwk/cafUserInterface/cafProgressInfo.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafProgressInfo.cpp @@ -76,7 +76,10 @@ ProgressInfo::ProgressInfo(size_t maxProgressValue, const QString& title) { ProgressInfoStatic::start(maxProgressValue, title); - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + if (qApp) + { + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + } } //-------------------------------------------------------------------------------------------------- @@ -86,7 +89,10 @@ ProgressInfo::~ProgressInfo() { ProgressInfoStatic::finished(); - QApplication::restoreOverrideCursor(); + if (qApp) + { + QApplication::restoreOverrideCursor(); + } } //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/VizFwk/CMake/Utils/ceeDetermineCompilerFlags.cmake b/Fwk/VizFwk/CMake/Utils/ceeDetermineCompilerFlags.cmake index 1ec1cd18d3..ae8dc3fcbb 100644 --- a/Fwk/VizFwk/CMake/Utils/ceeDetermineCompilerFlags.cmake +++ b/Fwk/VizFwk/CMake/Utils/ceeDetermineCompilerFlags.cmake @@ -69,7 +69,11 @@ if (MSVC) # Setup the our STRICT compile flags # These are the flags we would like to use on all of our own libraries - set(CEE_STRICT_CXX_FLAGS "${CEE_BASE_CXX_FLAGS} /Wall") + if (${MSVC_VERSION} LESS 1600) + set(CEE_STRICT_CXX_FLAGS "${CEE_BASE_CXX_FLAGS} /W4") + elseif() + set(CEE_STRICT_CXX_FLAGS "${CEE_BASE_CXX_FLAGS} /Wall") + endif() # Must add base warning level after setting up strict set(CEE_BASE_CXX_FLAGS "${CEE_BASE_CXX_FLAGS} /W3") diff --git a/Fwk/VizFwk/CMakeLists.txt b/Fwk/VizFwk/CMakeLists.txt index 2b45bb33c1..a799c645e1 100644 --- a/Fwk/VizFwk/CMakeLists.txt +++ b/Fwk/VizFwk/CMakeLists.txt @@ -23,6 +23,13 @@ if (CEE_STAND_ALONE) endif() +# Allow use of non-threadsafe reference counter in cvf::Object on systems with no atomics support +option(CEE_WORKAROUND_ON_SYSTEMS_WITHOUT_ATOMICS "Allow use of non-threadsafe reference counter on systems with no atomics support" OFF) +if (CEE_WORKAROUND_ON_SYSTEMS_WITHOUT_ATOMICS) + add_definitions(-DCVF_WORKAROUND_TO_COMPILE_ON_SYSTEMS_WITHOUT_ATOMICS) +endif() + + add_subdirectory(LibCore) add_subdirectory(LibIo) add_subdirectory(LibGeometry) diff --git a/Fwk/VizFwk/LibCore/CMakeLists.txt b/Fwk/VizFwk/LibCore/CMakeLists.txt index 4ec1da4fab..3ce19f6ec0 100644 --- a/Fwk/VizFwk/LibCore/CMakeLists.txt +++ b/Fwk/VizFwk/LibCore/CMakeLists.txt @@ -6,13 +6,13 @@ project(LibCore) # Use our strict compile flags set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CEE_STRICT_CXX_FLAGS}") - set(CEE_HEADER_FILES cvfArray.h cvfArray.inl cvfArrayWrapperConst.h cvfArrayWrapperToEdit.h cvfAssert.h +cvfAtomicCounter.h cvfBase.h cvfBase64.h cvfCharArray.h @@ -68,6 +68,7 @@ cvfVersion.h set(CEE_SOURCE_FILES cvfAssert.cpp +cvfAtomicCounter.cpp cvfBase64.cpp cvfCharArray.cpp cvfCodeLocation.cpp diff --git a/Fwk/VizFwk/LibCore/LibCore.vcxproj b/Fwk/VizFwk/LibCore/LibCore.vcxproj index 99bf0ca399..2e5f67e714 100644 --- a/Fwk/VizFwk/LibCore/LibCore.vcxproj +++ b/Fwk/VizFwk/LibCore/LibCore.vcxproj @@ -232,6 +232,7 @@ + @@ -290,6 +291,7 @@ + diff --git a/Fwk/VizFwk/LibCore/LibCore.vcxproj.filters b/Fwk/VizFwk/LibCore/LibCore.vcxproj.filters index 3146204a04..5d549ba813 100644 --- a/Fwk/VizFwk/LibCore/LibCore.vcxproj.filters +++ b/Fwk/VizFwk/LibCore/LibCore.vcxproj.filters @@ -45,6 +45,7 @@ + @@ -90,5 +91,6 @@ + - + \ No newline at end of file diff --git a/Fwk/VizFwk/LibCore/cvfArrayWrapperConst.h b/Fwk/VizFwk/LibCore/cvfArrayWrapperConst.h index 88049066b0..4d24812bf2 100644 --- a/Fwk/VizFwk/LibCore/cvfArrayWrapperConst.h +++ b/Fwk/VizFwk/LibCore/cvfArrayWrapperConst.h @@ -151,3 +151,4 @@ inline const ArrayWrapperConst< const ElmType*, ElmType > wrapArrayConst( ElmTy } } + diff --git a/Fwk/VizFwk/LibCore/cvfArrayWrapperToEdit.h b/Fwk/VizFwk/LibCore/cvfArrayWrapperToEdit.h index 4ac8558734..5f2ae1fc61 100644 --- a/Fwk/VizFwk/LibCore/cvfArrayWrapperToEdit.h +++ b/Fwk/VizFwk/LibCore/cvfArrayWrapperToEdit.h @@ -130,3 +130,4 @@ inline ArrayWrapperToEdit< ElmType*, ElmType > wrapArrayToEdit(ElmType* array, s } } + diff --git a/Fwk/VizFwk/LibCore/cvfAssert.cpp b/Fwk/VizFwk/LibCore/cvfAssert.cpp index bc74657cb5..8e33fcd7ea 100644 --- a/Fwk/VizFwk/LibCore/cvfAssert.cpp +++ b/Fwk/VizFwk/LibCore/cvfAssert.cpp @@ -113,9 +113,11 @@ Assert::FailAction AssertHandlerConsole::handleAssert(const char* fileName, int // Does the job on both Windows and Linux (creates a console on Windows if one doesn't exist) reportToConsole(fileName, lineNumber, expr, msg); -#ifdef WIN32 - if (::IsDebuggerPresent()) - { +#ifdef _MSC_VER +#if (_MSC_VER >= 1600) + if (::IsDebuggerPresent()) +#endif + { __debugbreak(); } #endif diff --git a/Fwk/VizFwk/LibCore/cvfAtomicCounter.cpp b/Fwk/VizFwk/LibCore/cvfAtomicCounter.cpp new file mode 100644 index 0000000000..2c6953eb09 --- /dev/null +++ b/Fwk/VizFwk/LibCore/cvfAtomicCounter.cpp @@ -0,0 +1,193 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2014 Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + +#include "cvfAtomicCounter.h" + +// Some older GCC version do not support atomics, we have seen this for RHEL5 +#if defined(CVF_ATOMIC_COUNTER_CLASS_EXISTS) + +namespace cvf { + +#ifdef WIN32 +#pragma warning (push) +#pragma warning (disable: 4668) +#include +#pragma warning (pop) + + +AtomicCounter::AtomicCounter(int initialValue) + : m_counter(initialValue) +{ +} + + +AtomicCounter::~AtomicCounter() +{ +} + + +AtomicCounter::operator int () const +{ + return m_counter; +} + +int AtomicCounter::operator ++ () // prefix +{ + return InterlockedIncrement(&m_counter); +} + + +int AtomicCounter::operator ++ (int) // postfix +{ + int result = InterlockedIncrement(&m_counter); + return --result; +} + + +int AtomicCounter::operator -- () // prefix +{ + return InterlockedDecrement(&m_counter); +} + + +int AtomicCounter::operator -- (int) // postfix +{ + int result = InterlockedDecrement(&m_counter); + return ++result; +} + + +#elif defined(CVF_IOS) || defined(CVF_OSX) + +AtomicCounter::AtomicCounter(int initialValue) + : m_counter(initialValue) +{ +} + + +AtomicCounter::AtomicCounter(const AtomicCounter& counter) + : m_counter(counter.value()) +{ +} + + +AtomicCounter::~AtomicCounter() +{ +} + +AtomicCounter::operator int () const +{ + return m_counter; +} + + +int AtomicCounter::operator ++ () // prefix +{ + return OSAtomicIncrement32(&m_counter); +} + + +int AtomicCounter::operator ++ (int) // postfix +{ + int result = OSAtomicIncrement32(&m_counter); + return --result; +} + + +int AtomicCounter::operator -- () // prefix +{ + return OSAtomicDecrement32(&m_counter); +} + + +int AtomicCounter::operator -- (int) // postfix +{ + int result = OSAtomicDecrement32(&m_counter); + return ++result; +} + + +#elif defined(CVF_GCC_DEFINED) + + +AtomicCounter::AtomicCounter(int initialValue) + : m_counter(initialValue) +{ +} + +AtomicCounter::~AtomicCounter() +{ +} + +AtomicCounter::operator int () const +{ + return m_counter; +} + + +int AtomicCounter::operator ++ () // prefix +{ + return __sync_add_and_fetch(&m_counter, 1); +} + + +int AtomicCounter::operator ++ (int) // postfix +{ + return __sync_fetch_and_add(&m_counter, 1); +} + + +int AtomicCounter::operator -- () // prefix +{ + return __sync_sub_and_fetch(&m_counter, 1); +} + + +int AtomicCounter::operator -- (int) // postfix +{ + return __sync_fetch_and_sub(&m_counter, 1); +} + + +#endif + + +} // namespace cvf + + + +#endif // CVF_ATOMICS_COMPILED diff --git a/Fwk/VizFwk/LibCore/cvfAtomicCounter.h b/Fwk/VizFwk/LibCore/cvfAtomicCounter.h new file mode 100644 index 0000000000..424e822b1a --- /dev/null +++ b/Fwk/VizFwk/LibCore/cvfAtomicCounter.h @@ -0,0 +1,91 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2014 Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + +#pragma once + +#include "cvfBase.h" + +#ifdef WIN32 + #define CVF_ATOMIC_COUNTER_CLASS_EXISTS +#elif defined(CVF_IOS) || defined(CVF_OSX) + #include + #define CVF_ATOMIC_COUNTER_CLASS_EXISTS +#elif defined __GNUC__ + #define CVF_GCC_DEFINED + #define CVF_ATOMIC_COUNTER_CLASS_EXISTS +#endif + +#if defined(CVF_ATOMIC_COUNTER_CLASS_EXISTS) + +namespace cvf { + +// Inspired by Poco + + +class AtomicCounter +{ +public: + explicit AtomicCounter(int initialValue); + ~AtomicCounter(); + + operator int () const; + + int operator ++ (); // prefix + int operator ++ (int); // postfix + + int operator -- (); // prefix + int operator -- (int); // postfix + +private: + + CVF_DISABLE_COPY_AND_ASSIGN(AtomicCounter); + +#ifdef WIN32 + typedef volatile long ImplType; +#elif defined(CVF_IOS) || defined(CVF_OSX) + typedef int32_t ImplType; +#else + typedef int ImplType; +#endif + + ImplType m_counter; +}; + + +} // namespace cvf + +#endif diff --git a/Fwk/VizFwk/LibCore/cvfBase.h b/Fwk/VizFwk/LibCore/cvfBase.h index 30970d05fb..6b6e8bf6e6 100644 --- a/Fwk/VizFwk/LibCore/cvfBase.h +++ b/Fwk/VizFwk/LibCore/cvfBase.h @@ -44,7 +44,7 @@ // Global include file with definitions useful for all library files // Disable some annoying warnings so we can compile with warning level Wall -#ifdef WIN32 +#ifdef _MSC_VER // 4512 'class' : assignment operator could not be generated : Due to problems with classes with reference member variables (e.g. VertexCompactor) // 4514 unreferenced inline/local function has been removed // 4625 copy constructor could not be generated because a base class copy constructor is inaccessible @@ -54,13 +54,26 @@ // 4711 function 'func_name' selected for automatic inline expansion // 4738 storing 32-bit float result in memory, possible loss of performance // 4820 'bytes' bytes padding added after construct 'member_name' +#pragma warning (disable: 4512 4514 4625 4626 4640 4710 4711 4738 4820) + +#if (_MSC_VER >= 1600) +// VS2010 and newer // 4986 'operator new[]': exception specification does not match previous declaration -#pragma warning (disable: 4512 4514 4625 4626 4640 4710 4711 4738 4820 4986) +#pragma warning (disable: 4986) +#endif + #endif + +// Makes it easier to check on the current GCC version +#ifdef __GNUC__ +// 40302 means version 4.3.2. +# define CVF_GCC_VER (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) +#endif + // Helper macro to disable (ignore) compiler warnings on GCC // The needed pragma is only available in GCC for versions 4.2.x and above -#if defined __GNUC__ && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 402) +#if defined(__GNUC__) && (CVF_GCC_VER >= 40200) #define CVF_DO_PRAGMA(x) _Pragma(#x) #define CVF_GCC_DIAGNOSTIC_IGNORE(OPTION_STRING) CVF_DO_PRAGMA(GCC diagnostic ignored OPTION_STRING) #else diff --git a/Fwk/VizFwk/LibCore/cvfObject.h b/Fwk/VizFwk/LibCore/cvfObject.h index 9ff28e7ad6..b048228b0f 100644 --- a/Fwk/VizFwk/LibCore/cvfObject.h +++ b/Fwk/VizFwk/LibCore/cvfObject.h @@ -41,6 +41,11 @@ #include +#include "cvfAtomicCounter.h" + +#if !defined(CVF_ATOMIC_COUNTER_CLASS_EXISTS) && !defined(CVF_USE_NON_THREADSAFE_REFERENCE_COUNT) +#error No support for atomics. Define CVF_USE_NON_THREADSAFE_REFERENCE_COUNT to be able to compile +#endif namespace cvf { @@ -65,7 +70,15 @@ class Object static void dumpActiveObjectInstances(); private: + +#if defined(CVF_USE_NON_THREADSAFE_REFERENCE_COUNT) mutable int m_refCount; +#elif defined(CVF_ATOMIC_COUNTER_CLASS_EXISTS) + mutable AtomicCounter m_refCount; +#else + #error No support for atomics. Define CVF_USE_NON_THREADSAFE_REFERENCE_COUNT to be able to compile +#endif + CVF_DISABLE_COPY_AND_ASSIGN(Object); }; diff --git a/Fwk/VizFwk/LibCore/cvfObject.inl b/Fwk/VizFwk/LibCore/cvfObject.inl index a4c65fd573..59bf9dbf38 100644 --- a/Fwk/VizFwk/LibCore/cvfObject.inl +++ b/Fwk/VizFwk/LibCore/cvfObject.inl @@ -91,9 +91,7 @@ inline int Object::release() const CVF_TIGHT_ASSERT(m_refCount > 0); - m_refCount--; - - if (m_refCount == 0) + if (--m_refCount == 0) { delete this; return 0; diff --git a/Fwk/VizFwk/LibCore/cvfPlane.cpp b/Fwk/VizFwk/LibCore/cvfPlane.cpp index dcb523125a..7a39f37fc8 100644 --- a/Fwk/VizFwk/LibCore/cvfPlane.cpp +++ b/Fwk/VizFwk/LibCore/cvfPlane.cpp @@ -205,7 +205,7 @@ bool Plane::setFromPointAndNormal(const Vec3d& point, const Vec3d& normal) /// \param p2 Second point on the plane /// \param p3 Third point on the plane /// -/// \return true if successfully set. false if points are on the same line. +/// \return true if successfully set. false if points are on the same line. /// /// The three points must be different from each other and cannot be on the same line in space //-------------------------------------------------------------------------------------------------- @@ -322,7 +322,7 @@ double Plane::distanceToOrigin() const /// \param vector Vector to be projected /// \param projectedVector Projected vector to be returned by pointer /// -/// \return true if successfully projected. +/// \return true if successfully projected. /// false if the given \a vector is parallel with the plane's normal //-------------------------------------------------------------------------------------------------- bool Plane::projectVector(const Vec3d& vector, Vec3d* projectedVector) const @@ -378,7 +378,7 @@ Vec3d Plane::projectPoint(const Vec3d& point) const /// \param point Point on line /// \param direction Normalized direction of line /// -/// \return true if success. false if direction is zero -> no point of intersection exists +/// \return true if success. false if direction is zero -> no point of intersection exists //-------------------------------------------------------------------------------------------------- bool Plane::intersect(const Plane& other, Vec3d* point, Vec3d* direction) const { @@ -474,6 +474,125 @@ bool Plane::intersect(const Vec3d& a, const Vec3d& b, Vec3d* intersection) const return false; } + + +//-------------------------------------------------------------------------------------------------- +/// Clip a triangle against this plane +/// +/// Clip the triangle given by parameters a, b and c against this plane. The vertices of the +/// resulting clipped polygon (triangle or quad) will be returned in \a clippedPolygon. Since the +/// clipped polygon may be a quad, the \a clippedPolygon array must have room for at least 4 elements. +/// +/// \return The number of resulting vertices that are populated in \a clippedPolygon. Will be 0, 3 or 4. +//-------------------------------------------------------------------------------------------------- +size_t Plane::clipTriangle(const Vec3d& a, const Vec3d& b, const Vec3d& c, Vec3d clippedPolygon[4]) const +{ + // Except for the trivial cases where all vertices are in front + // or behind plane, these are the permutations + // + // Single vertex on positive side of plane + // => return a triangle + // + // +\ /\c /\c /+ /\c . + // \ / \ / \ / + / \ + . + // \ \ / \/ ---/----\--- . + // / \ \ / /\ / \ . + // a/___\____\b a/_____/__\b a/________\b . + // +\ /+ + // + // Two vertices vertex on positive side of plane + // => return a quad + // + // /\c \+ /\c /\c +/ . + // / \ \ / \ / \ / . + // ___/____\___ \ \ / \/ . + // + / \ + / \ \ / /\ . + // a/________\b a/___\____\b a/_____/__\b . + // \+ +/ + + bool onPosSide[3]; + onPosSide[0] = distanceSquared(a) >= 0 ? true : false; + onPosSide[1] = distanceSquared(b) >= 0 ? true : false; + onPosSide[2] = distanceSquared(c) >= 0 ? true : false; + const int numPositiveVertices = (onPosSide[0] ? 1 : 0) + (onPosSide[1] ? 1 : 0) + (onPosSide[2] ? 1 : 0); + + // The entire triangle is on the negative side + // Clip everything + if (numPositiveVertices == 0) + { + return 0; + } + + // All triangle vertices are on the positive side + // Return the same triangle + if (numPositiveVertices == 3) + { + clippedPolygon[0] = a; + clippedPolygon[1] = b; + clippedPolygon[2] = c; + return 3; + } + + // Handle case where a single vertex is on the positive side + // Will result in the return of a single clipped triangle + if (numPositiveVertices == 1) + { + if (onPosSide[0]) + { + clippedPolygon[0] = a; + intersect(a, b, &clippedPolygon[1]); + intersect(a, c, &clippedPolygon[2]); + } + else if (onPosSide[1]) + { + clippedPolygon[0] = b; + intersect(b, c, &clippedPolygon[1]); + intersect(b, a, &clippedPolygon[2]); + } + else + { + CVF_ASSERT(onPosSide[2]); + clippedPolygon[0] = c; + intersect(c, a, &clippedPolygon[1]); + intersect(c, b, &clippedPolygon[2]); + } + + return 3; + } + else + { + CVF_ASSERT(numPositiveVertices == 2); + if (onPosSide[0] && onPosSide[1]) + { + // a & b are on positive side + clippedPolygon[0] = a; + clippedPolygon[1] = b; + intersect(b, c, &clippedPolygon[2]); + intersect(a, c, &clippedPolygon[3]); + } + else if (onPosSide[1] && onPosSide[2]) + { + // b & c are on positive side + clippedPolygon[0] = b; + clippedPolygon[1] = c; + intersect(c, a, &clippedPolygon[2]); + intersect(b, a, &clippedPolygon[3]); + } + else + { + // c && a are on positive side + CVF_ASSERT(onPosSide[2] && onPosSide[0]); + clippedPolygon[0] = c; + clippedPolygon[1] = a; + intersect(a, b, &clippedPolygon[2]); + intersect(c, b, &clippedPolygon[3]); + } + + return 4; + } +} + + //-------------------------------------------------------------------------------------------------- /// Classify where the point is located relative to the plane /// diff --git a/Fwk/VizFwk/LibCore/cvfPlane.h b/Fwk/VizFwk/LibCore/cvfPlane.h index 0ce4614d69..c44bf8ebee 100644 --- a/Fwk/VizFwk/LibCore/cvfPlane.h +++ b/Fwk/VizFwk/LibCore/cvfPlane.h @@ -91,7 +91,8 @@ class Plane : public Object bool intersect(const Plane& other, Vec3d* point, Vec3d* direction = NULL) const; bool intersect(const Vec3d& a, const Vec3d& b, Vec3d* intersection) const; - + size_t clipTriangle(const Vec3d& ta, const Vec3d& tb, const Vec3d& tc, Vec3d clippedPolygon[4]) const; + Side side(const Vec3d& point) const; Side side(const Vec3dArray& points) const; diff --git a/Fwk/VizFwk/LibCore/cvfVector2.h b/Fwk/VizFwk/LibCore/cvfVector2.h index 0bf1806b67..720dceab45 100644 --- a/Fwk/VizFwk/LibCore/cvfVector2.h +++ b/Fwk/VizFwk/LibCore/cvfVector2.h @@ -108,6 +108,8 @@ class Vector2 inline S lengthSquared() const; bool setLength(S newLength); + const Vector2 perpendicularVector() const; + public: static const Vector2 X_AXIS; ///< X axis vector <1, 0> static const Vector2 Y_AXIS; ///< Y axis vector <0, 1> diff --git a/Fwk/VizFwk/LibCore/cvfVector2.inl b/Fwk/VizFwk/LibCore/cvfVector2.inl index 7a74ae73d2..90271c2c16 100644 --- a/Fwk/VizFwk/LibCore/cvfVector2.inl +++ b/Fwk/VizFwk/LibCore/cvfVector2.inl @@ -394,6 +394,27 @@ bool Vector2::setLength(S newLength) } +//-------------------------------------------------------------------------------------------------- +/// Return a unit length perpendicular vector +/// +/// Returns the vector (y,-x), normalized. This can be thought of as the 'right' vector. +//-------------------------------------------------------------------------------------------------- +template +const Vector2 Vector2::perpendicularVector() const +{ + S len = length(); + if (len > 0.0) + { + S oneOverLen = (static_cast(1.0)/len); + return Vector2(m_v[1]*oneOverLen, -m_v[0]*oneOverLen); + } + else + { + return Vector2::ZERO; + } +} + + //-------------------------------------------------------------------------------------------------- /// Normalize the vector (make sure the length is 1.0). /// diff --git a/Fwk/VizFwk/LibGeometry/CMakeLists.txt b/Fwk/VizFwk/LibGeometry/CMakeLists.txt index 20eceb2ff9..6034118a2c 100644 --- a/Fwk/VizFwk/LibGeometry/CMakeLists.txt +++ b/Fwk/VizFwk/LibGeometry/CMakeLists.txt @@ -25,6 +25,7 @@ cvfLibGeometry.h cvfMeshEdgeExtractor.h cvfOutlineEdgeExtractor.h cvfPatchGenerator.h +cvfPrimitiveTests.h cvfRay.h cvfTriangleMeshEdgeExtractor.h cvfTriangleVertexSplitter.h @@ -46,6 +47,7 @@ cvfGeometryUtils.cpp cvfMeshEdgeExtractor.cpp cvfOutlineEdgeExtractor.cpp cvfPatchGenerator.cpp +cvfPrimitiveTests.cpp cvfRay.cpp cvfTriangleMeshEdgeExtractor.cpp cvfTriangleVertexSplitter.cpp diff --git a/Fwk/VizFwk/LibGeometry/LibGeometry.vcxproj b/Fwk/VizFwk/LibGeometry/LibGeometry.vcxproj index 1ab7b75a2e..fdea6f8510 100644 --- a/Fwk/VizFwk/LibGeometry/LibGeometry.vcxproj +++ b/Fwk/VizFwk/LibGeometry/LibGeometry.vcxproj @@ -253,6 +253,7 @@ + @@ -273,6 +274,7 @@ + diff --git a/Fwk/VizFwk/LibGeometry/LibGeometry.vcxproj.filters b/Fwk/VizFwk/LibGeometry/LibGeometry.vcxproj.filters index 3ea51aeeb0..c5b73ae9b8 100644 --- a/Fwk/VizFwk/LibGeometry/LibGeometry.vcxproj.filters +++ b/Fwk/VizFwk/LibGeometry/LibGeometry.vcxproj.filters @@ -20,6 +20,7 @@ + @@ -43,5 +44,6 @@ + \ No newline at end of file diff --git a/Fwk/VizFwk/LibGeometry/cvfPrimitiveTests.cpp b/Fwk/VizFwk/LibGeometry/cvfPrimitiveTests.cpp new file mode 100644 index 0000000000..4dc0f2ba83 --- /dev/null +++ b/Fwk/VizFwk/LibGeometry/cvfPrimitiveTests.cpp @@ -0,0 +1,106 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + +#include "cvfBase.h" +#include "cvfPrimitiveTests.h" + +#include + +namespace cvf { + + + +//================================================================================================== +/// +/// \class cvf::PrimitiveTests +/// \ingroup Geometry +/// +/// +/// +//================================================================================================== + + + +//-------------------------------------------------------------------------------------------------- +/// Calculate intersection between the lines p1p2 and p3p4 +//-------------------------------------------------------------------------------------------------- +bool PrimitiveTests::intersectLines(const Vec2d& p1, const Vec2d& p2, const Vec2d& p3, const Vec2d& p4, Vec2d* isect) +{ + // See Paul Bourke, Intersection point of two lines in 2 dimensions + + const double epsilon = std::numeric_limits::epsilon(); + + const double denom = (p4.y()-p3.y())*(p2.x()-p1.x()) - (p4.x()-p3.x())*(p2.y()-p1.y()); + const double numera = (p4.x()-p3.x())*(p1.y()-p3.y()) - (p4.y()-p3.y())*(p1.x()-p3.x()); + const double numerb = (p2.x()-p1.x())*(p1.y()-p3.y()) - (p2.y()-p1.y())*(p1.x()-p3.x()); + + // Are the lines coincident? + if (cvf::Math::abs(numera) < epsilon && + cvf::Math::abs(numerb) < epsilon && + cvf::Math::abs(denom) < epsilon) + { + isect->x() = (p1.x() + p2.x()) / 2; + isect->y() = (p1.y() + p2.y()) / 2; + return true; + } + + // Are the lines parallel? + if (cvf::Math::abs(denom) < epsilon) + { + isect->setZero(); + return false; + } + + const double ta = numera/denom; +// const double tb = numerb/denom; +// +// // Is the intersection along the the segments ? +// if (ta < 0 || ta > 1 || tb < 0 || tb > 1) +// { +// isect->setZero(); +// return false; +// } + + isect->x() = p1.x() + ta * (p2.x() - p1.x()); + isect->y() = p1.y() + ta * (p2.y() - p1.y()); + + return true; + +} + + +} // namespace cvf diff --git a/Fwk/VizFwk/LibGeometry/cvfPrimitiveTests.h b/Fwk/VizFwk/LibGeometry/cvfPrimitiveTests.h new file mode 100644 index 0000000000..a366ff6818 --- /dev/null +++ b/Fwk/VizFwk/LibGeometry/cvfPrimitiveTests.h @@ -0,0 +1,56 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + +#pragma once + +#include "cvfVector2.h" + +namespace cvf { + + +//================================================================================================== +// +// +// +//================================================================================================== +class PrimitiveTests +{ +public: + static bool intersectLines(const Vec2d& p1, const Vec2d& p2, const Vec2d& p3, const Vec2d& p4, Vec2d* isect); +}; + +} diff --git a/Fwk/VizFwk/LibGuiQt/cvfqtMouseState.h b/Fwk/VizFwk/LibGuiQt/cvfqtMouseState.h index 406c6909a0..fc6c39cafc 100644 --- a/Fwk/VizFwk/LibGuiQt/cvfqtMouseState.h +++ b/Fwk/VizFwk/LibGuiQt/cvfqtMouseState.h @@ -40,7 +40,8 @@ class QMouseEvent; class QGraphicsSceneMouseEvent; -#include +#include + namespace cvfqt { diff --git a/Fwk/VizFwk/LibRender/LibRender.vcxproj b/Fwk/VizFwk/LibRender/LibRender.vcxproj index d83878465b..0aeca74699 100644 --- a/Fwk/VizFwk/LibRender/LibRender.vcxproj +++ b/Fwk/VizFwk/LibRender/LibRender.vcxproj @@ -463,7 +463,12 @@ Document - + + Document + + + Document + diff --git a/Fwk/VizFwk/LibRender/LibRender.vcxproj.filters b/Fwk/VizFwk/LibRender/LibRender.vcxproj.filters index 3b5dabfa44..c511a1afa1 100644 --- a/Fwk/VizFwk/LibRender/LibRender.vcxproj.filters +++ b/Fwk/VizFwk/LibRender/LibRender.vcxproj.filters @@ -186,15 +186,18 @@ + + glsl + + + glsl + glsl - - glsl - diff --git a/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.cpp b/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.cpp index 66a011a8c3..67eee1594c 100644 --- a/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.cpp +++ b/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.cpp @@ -119,6 +119,7 @@ const char* ShaderSourceRepository::shaderIdentString(ShaderIdent shaderIdent) CVF_IDENT_HANDLE_CASE(src_TextureGlobalAlpha); CVF_IDENT_HANDLE_CASE(src_TextureFromPointCoord); CVF_IDENT_HANDLE_CASE(src_TextureRectFromFragCoord_v33); + CVF_IDENT_HANDLE_CASE(src_VaryingColorGlobalAlpha); CVF_IDENT_HANDLE_CASE(light_Phong); CVF_IDENT_HANDLE_CASE(light_PhongDual); @@ -179,6 +180,7 @@ bool ShaderSourceRepository::rawShaderSource(ShaderIdent shaderIdent, CharArray* CVF_SOURCE_HANDLE_CASE(src_TextureGlobalAlpha); CVF_SOURCE_HANDLE_CASE(src_TextureFromPointCoord); CVF_SOURCE_HANDLE_CASE(src_TextureRectFromFragCoord_v33); + CVF_SOURCE_HANDLE_CASE(src_VaryingColorGlobalAlpha); CVF_SOURCE_HANDLE_CASE(light_Phong); CVF_SOURCE_HANDLE_CASE(light_PhongDual); diff --git a/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.h b/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.h index e20c7a4870..bacf13cb42 100644 --- a/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.h +++ b/Fwk/VizFwk/LibRender/cvfShaderSourceRepository.h @@ -64,6 +64,7 @@ class ShaderSourceRepository : public Object src_TextureGlobalAlpha, src_TextureFromPointCoord, src_TextureRectFromFragCoord_v33, + src_VaryingColorGlobalAlpha, light_Phong, light_PhongDual, diff --git a/Fwk/VizFwk/LibRender/cvfShaderSourceStrings.h b/Fwk/VizFwk/LibRender/cvfShaderSourceStrings.h index ac3c2b8bb8..c6a027a8ab 100644 --- a/Fwk/VizFwk/LibRender/cvfShaderSourceStrings.h +++ b/Fwk/VizFwk/LibRender/cvfShaderSourceStrings.h @@ -914,6 +914,24 @@ static const char src_TwoSidedColor_inl[] = +//############################################################################################################################# +//############################################################################################################################# +static const char src_VaryingColorGlobalAlpha_inl[] = +" \n" +"uniform float u_alpha; \n" +" \n" +"varying vec4 v_color; \n" +" \n" +"//-------------------------------------------------------------------------------------------------- \n" +"/// RGB color from varying, alpha from uniform \n" +"//-------------------------------------------------------------------------------------------------- \n" +"vec4 srcFragment() \n" +"{ \n" +" return vec4(v_color.rgb, u_alpha); \n" +"} \n"; + + + //############################################################################################################################# //############################################################################################################################# static const char vs_DistanceScaledPoints_inl[] = @@ -1147,10 +1165,12 @@ static const char vs_Standard_inl[] = "attribute vec4 cvfa_vertex; \n" "attribute vec3 cvfa_normal; \n" "attribute vec2 cvfa_texCoord; \n" +"attribute vec4 cvfa_color; \n" " \n" "varying vec3 v_ecPosition; \n" "varying vec3 v_ecNormal; \n" "varying vec2 v_texCoord; \n" +"varying vec4 v_color; \n" " \n" "//-------------------------------------------------------------------------------------------------- \n" "/// Vertex Shader - Standard \n" @@ -1165,6 +1185,7 @@ static const char vs_Standard_inl[] = " v_ecPosition = (cvfu_modelViewMatrix * cvfa_vertex).xyz; \n" " v_ecNormal = cvfu_normalMatrix * cvfa_normal; \n" " v_texCoord = cvfa_texCoord; \n" +" v_color = cvfa_color; \n" " \n" "#ifdef CVF_CALC_CLIP_DISTANCES_IMPL \n" " calcClipDistances(vec4(v_ecPosition, 1)); \n" diff --git a/Fwk/VizFwk/LibRender/glsl/src_VaryingColorGlobalAlpha.glsl b/Fwk/VizFwk/LibRender/glsl/src_VaryingColorGlobalAlpha.glsl new file mode 100644 index 0000000000..d316fd0a9c --- /dev/null +++ b/Fwk/VizFwk/LibRender/glsl/src_VaryingColorGlobalAlpha.glsl @@ -0,0 +1,12 @@ + +uniform float u_alpha; + +varying vec4 v_color; + +//-------------------------------------------------------------------------------------------------- +/// RGB color from varying, alpha from uniform +//-------------------------------------------------------------------------------------------------- +vec4 srcFragment() +{ + return vec4(v_color.rgb, u_alpha); +} \ No newline at end of file diff --git a/Fwk/VizFwk/LibRender/glsl/vs_Standard.glsl b/Fwk/VizFwk/LibRender/glsl/vs_Standard.glsl index d02613fb4f..0463877e69 100644 --- a/Fwk/VizFwk/LibRender/glsl/vs_Standard.glsl +++ b/Fwk/VizFwk/LibRender/glsl/vs_Standard.glsl @@ -6,10 +6,12 @@ uniform mat3 cvfu_normalMatrix; attribute vec4 cvfa_vertex; attribute vec3 cvfa_normal; attribute vec2 cvfa_texCoord; +attribute vec4 cvfa_color; varying vec3 v_ecPosition; varying vec3 v_ecNormal; varying vec2 v_texCoord; +varying vec4 v_color; //-------------------------------------------------------------------------------------------------- /// Vertex Shader - Standard @@ -24,6 +26,7 @@ void main () v_ecPosition = (cvfu_modelViewMatrix * cvfa_vertex).xyz; v_ecNormal = cvfu_normalMatrix * cvfa_normal; v_texCoord = cvfa_texCoord; + v_color = cvfa_color; #ifdef CVF_CALC_CLIP_DISTANCES_IMPL calcClipDistances(vec4(v_ecPosition, 1)); diff --git a/Fwk/VizFwk/LibUtilities/cvfuImageTga.cpp b/Fwk/VizFwk/LibUtilities/cvfuImageTga.cpp index 606742687d..5abf548a6e 100644 --- a/Fwk/VizFwk/LibUtilities/cvfuImageTga.cpp +++ b/Fwk/VizFwk/LibUtilities/cvfuImageTga.cpp @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: @@ -44,12 +44,13 @@ #include #include -#ifdef CVF_LINUX CVF_GCC_DIAGNOSTIC_IGNORE("-Wconversion") + +// Apparently, this warning doesn't exist until GCC 4.5 +#if defined(__GNUC__) && (CVF_GCC_VER >= 40500) CVF_GCC_DIAGNOSTIC_IGNORE("-Wunused-result") #endif - namespace cvfu { using cvf::ref; diff --git a/Fwk/VizFwk/LibUtilities/cvfuImageTga.h b/Fwk/VizFwk/LibUtilities/cvfuImageTga.h index 4c3dbb1a3c..2afb3d8fb8 100644 --- a/Fwk/VizFwk/LibUtilities/cvfuImageTga.h +++ b/Fwk/VizFwk/LibUtilities/cvfuImageTga.h @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: diff --git a/Fwk/VizFwk/LibViewing/cvfModelBasicList.cpp b/Fwk/VizFwk/LibViewing/cvfModelBasicList.cpp index 946aaa64f3..c9c56f2c7f 100644 --- a/Fwk/VizFwk/LibViewing/cvfModelBasicList.cpp +++ b/Fwk/VizFwk/LibViewing/cvfModelBasicList.cpp @@ -126,6 +126,16 @@ void ModelBasicList::removeAllParts() } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void ModelBasicList::shrinkPartCount(size_t newPartCount) +{ + CVF_ASSERT(newPartCount <= m_parts.size()); + m_parts.resize(newPartCount); +} + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/VizFwk/LibViewing/cvfModelBasicList.h b/Fwk/VizFwk/LibViewing/cvfModelBasicList.h index 4f26a5c04b..d4083a707b 100644 --- a/Fwk/VizFwk/LibViewing/cvfModelBasicList.h +++ b/Fwk/VizFwk/LibViewing/cvfModelBasicList.h @@ -60,6 +60,7 @@ class ModelBasicList : public Model size_t partCount() const; void removePart(Part* part); void removeAllParts(); + void shrinkPartCount(size_t newPartCount); virtual void findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, uint enableMask); virtual void allParts(Collection* partCollection); diff --git a/Fwk/VizFwk/Tests/LibCore_UnitTests/CMakeLists.txt b/Fwk/VizFwk/Tests/LibCore_UnitTests/CMakeLists.txt index 6179f39079..d9bdf9d046 100644 --- a/Fwk/VizFwk/Tests/LibCore_UnitTests/CMakeLists.txt +++ b/Fwk/VizFwk/Tests/LibCore_UnitTests/CMakeLists.txt @@ -14,6 +14,7 @@ set(CEE_LIBS LibCore) set(CEE_SOURCE_FILES cvfArray-Test.cpp cvfArrayWrapper-Test.cpp +cvfAtomicCounter-Test.cpp cvfBase-Test.cpp cvfBase64-Test.cpp cvfCharArray-Test.cpp diff --git a/Fwk/VizFwk/Tests/LibCore_UnitTests/LibCore_UnitTests.vcxproj b/Fwk/VizFwk/Tests/LibCore_UnitTests/LibCore_UnitTests.vcxproj index f3df0af7a1..af7fad5028 100644 --- a/Fwk/VizFwk/Tests/LibCore_UnitTests/LibCore_UnitTests.vcxproj +++ b/Fwk/VizFwk/Tests/LibCore_UnitTests/LibCore_UnitTests.vcxproj @@ -251,6 +251,7 @@ + diff --git a/Fwk/VizFwk/Tests/LibCore_UnitTests/LibCore_UnitTests.vcxproj.filters b/Fwk/VizFwk/Tests/LibCore_UnitTests/LibCore_UnitTests.vcxproj.filters index ff7ac81000..2355343553 100644 --- a/Fwk/VizFwk/Tests/LibCore_UnitTests/LibCore_UnitTests.vcxproj.filters +++ b/Fwk/VizFwk/Tests/LibCore_UnitTests/LibCore_UnitTests.vcxproj.filters @@ -34,6 +34,7 @@ + @@ -41,4 +42,4 @@ - + \ No newline at end of file diff --git a/Fwk/VizFwk/Tests/LibCore_UnitTests/cvfArrayWrapper-Test.cpp b/Fwk/VizFwk/Tests/LibCore_UnitTests/cvfArrayWrapper-Test.cpp index da06193796..bb9cba7996 100644 --- a/Fwk/VizFwk/Tests/LibCore_UnitTests/cvfArrayWrapper-Test.cpp +++ b/Fwk/VizFwk/Tests/LibCore_UnitTests/cvfArrayWrapper-Test.cpp @@ -123,10 +123,10 @@ TEST(ArrayWrapperTest, AllSpecializations) siztCvfArray[0] = 0; siztCvfArray[1] = 1; - cvf::Array uintCvfArray(2); + cvf::Array uintCvfArray(2); uintCvfArray[0] = 0; uintCvfArray[1] = 1; - const cvf::Array& cuintCvfArray = uintCvfArray; + const cvf::Array& cuintCvfArray = uintCvfArray; size_t siztBarePtrArray[2] = {0, 1}; @@ -187,3 +187,4 @@ TEST(ArrayWrapperTest, AllSpecializations) EXPECT_EQ(0.0, doubleBarePtr[1]); EXPECT_EQ(1.0, doubleBarePtr[0]); } + diff --git a/Fwk/VizFwk/Tests/LibCore_UnitTests/cvfAtomicCounter-Test.cpp b/Fwk/VizFwk/Tests/LibCore_UnitTests/cvfAtomicCounter-Test.cpp new file mode 100644 index 0000000000..1899a2141b --- /dev/null +++ b/Fwk/VizFwk/Tests/LibCore_UnitTests/cvfAtomicCounter-Test.cpp @@ -0,0 +1,141 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2014 Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + + +#include "cvfAtomicCounter.h" + +#ifdef CVF_ATOMIC_COUNTER_CLASS_EXISTS + +#include "cvfDebugTimer.h" +#include "cvfObject.h" +#include "cvfCollection.h" + +#include "gtest/gtest.h" + +using namespace cvf; + +class MyObj : public Object +{ +public: + MyObj() { num_ = 0; } + MyObj(int num) { num_ = num; } + + int num() const { return num_; } + void num(int num) { num_ = num; } + + bool operator<(const MyObj& rhs) + { + return num_ < rhs.num_; + } + +private: + int num_; +}; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(DISABLED_ObjectConstructionBenchmark, TestBasicObjectConstruction) +{ + int objectCount = 1000000; + int iterationCount = 5; + + String sNumber(objectCount); + String refCountTxt = String("TestBasicObjectConstruction : ") + sNumber; + DebugTimer tim(refCountTxt.toAscii().ptr()); + + for (int iteration = 0; iteration < iterationCount; iteration++) + { + for (int i = 0; i < objectCount; i++) + { + MyObj* r2 = new MyObj(); + + r2->addRef(); + r2->release(); + } + + tim.reportLapTimeMS(); + } +} + + + +class ObjectReferencingSharedObject : public Object +{ +public: + ObjectReferencingSharedObject() { } + + cvf::ref m_sharedObject; +}; + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(DISABLED_ObjectConstructionBenchmark, TestReferenceOtherObject) +{ + int objectCount = 1000000; + int iterationCount = 5; + + String sNumber(objectCount); + String refCountTxt = String("TestReferenceOtherObjectClass : ") + sNumber; + DebugTimer tim(refCountTxt.toAscii().ptr()); + + for (int iteration = 0; iteration < iterationCount; iteration++) + { + cvf::ref sharedObj = new MyObj(); + + std::vector< cvf::ref > col; + col.resize(objectCount); + + for (int i = 0; i < objectCount; i++) + { + cvf::ref newObj = new ObjectReferencingSharedObject(); + newObj->m_sharedObject = sharedObj.p(); + + col[i] = newObj; + } + + String sNumber(sharedObj->refCount()); + String refCountTxt = String("Shared object reference count : ") + sNumber; + + tim.reportLapTimeMS(refCountTxt.toAscii().ptr()); + } +} + + +#endif //#ifdef CVF_ATOMIC_COUNTER_CLASS_EXISTS diff --git a/Fwk/VizFwk/Tests/LibCore_UnitTests/cvfVector2-Test.cpp b/Fwk/VizFwk/Tests/LibCore_UnitTests/cvfVector2-Test.cpp index 74580e733e..8bde8cd375 100644 --- a/Fwk/VizFwk/Tests/LibCore_UnitTests/cvfVector2-Test.cpp +++ b/Fwk/VizFwk/Tests/LibCore_UnitTests/cvfVector2-Test.cpp @@ -365,6 +365,38 @@ TEST(Vector2Test, SetLength) } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(Vector2Test, perpendicularVector) +{ + { + const Vec2d v(0, 1); + const Vec2d perp = v.perpendicularVector(); + EXPECT_DOUBLE_EQ(1, perp.x()); + EXPECT_DOUBLE_EQ(0, perp.y()); + } + { + const Vec2d v(1, 0); + const Vec2d perp = v.perpendicularVector(); + EXPECT_DOUBLE_EQ(0, perp.x()); + EXPECT_DOUBLE_EQ(-1, perp.y()); + } + { + const Vec2d v(0, -2); + const Vec2d perp = v.perpendicularVector(); + EXPECT_DOUBLE_EQ(-1, perp.x()); + EXPECT_DOUBLE_EQ(0, perp.y()); + } + { + const Vec2d v(-3, 0); + const Vec2d perp = v.perpendicularVector(); + EXPECT_DOUBLE_EQ(0, perp.x()); + EXPECT_DOUBLE_EQ(1, perp.y()); + } +} + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/VizFwk/Tests/LibGeometry_UnitTests/CMakeLists.txt b/Fwk/VizFwk/Tests/LibGeometry_UnitTests/CMakeLists.txt index d7c1a6939d..3db9d045ff 100644 --- a/Fwk/VizFwk/Tests/LibGeometry_UnitTests/CMakeLists.txt +++ b/Fwk/VizFwk/Tests/LibGeometry_UnitTests/CMakeLists.txt @@ -26,6 +26,7 @@ cvfGeometryUtils-Test.cpp cvfMeshEdgeExtractor-Test.cpp cvfOutlineEdgeExtractor-Test.cpp cvfPatchGenerator-Test.cpp +cvfPrimitiveTests-Test.cpp cvfRay-Test.cpp cvfTriangleMeshEdgeExtractor-Test.cpp cvfTriangleVertexSplitter-Test.cpp diff --git a/Fwk/VizFwk/Tests/LibGeometry_UnitTests/LibGeometry_UnitTests.vcxproj b/Fwk/VizFwk/Tests/LibGeometry_UnitTests/LibGeometry_UnitTests.vcxproj index 5fa9ba7f0b..db6873009a 100644 --- a/Fwk/VizFwk/Tests/LibGeometry_UnitTests/LibGeometry_UnitTests.vcxproj +++ b/Fwk/VizFwk/Tests/LibGeometry_UnitTests/LibGeometry_UnitTests.vcxproj @@ -262,6 +262,7 @@ + diff --git a/Fwk/VizFwk/Tests/LibGeometry_UnitTests/LibGeometry_UnitTests.vcxproj.filters b/Fwk/VizFwk/Tests/LibGeometry_UnitTests/LibGeometry_UnitTests.vcxproj.filters index 705fcf6348..3bb24304be 100644 --- a/Fwk/VizFwk/Tests/LibGeometry_UnitTests/LibGeometry_UnitTests.vcxproj.filters +++ b/Fwk/VizFwk/Tests/LibGeometry_UnitTests/LibGeometry_UnitTests.vcxproj.filters @@ -21,6 +21,7 @@ + diff --git a/Fwk/VizFwk/Tests/LibGeometry_UnitTests/cvfPrimitiveTests-Test.cpp b/Fwk/VizFwk/Tests/LibGeometry_UnitTests/cvfPrimitiveTests-Test.cpp new file mode 100644 index 0000000000..313285b108 --- /dev/null +++ b/Fwk/VizFwk/Tests/LibGeometry_UnitTests/cvfPrimitiveTests-Test.cpp @@ -0,0 +1,90 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2013 Ceetron AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + +#include "cvfBase.h" +#include "cvfPrimitiveTests.h" + +#include "gtest/gtest.h" + +using namespace cvf; + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(PrimitiveTestsTest, intersectLines) +{ + { + Vec2d p1(0, 0); Vec2d p2(2, 0); + Vec2d p3(1, -1); Vec2d p4(1, 1); + Vec2d isect(0, 0); + EXPECT_TRUE(PrimitiveTests::intersectLines(p1, p2, p3, p4, &isect)); + EXPECT_DOUBLE_EQ(1, isect.x()); + EXPECT_DOUBLE_EQ(0, isect.y()); + } + + { + Vec2d p1(0, 0); Vec2d p2(2, 0); + Vec2d p3(1, 2); Vec2d p4(1, 1); + Vec2d isect(0, 0); + EXPECT_TRUE(PrimitiveTests::intersectLines(p1, p2, p3, p4, &isect)); + EXPECT_DOUBLE_EQ(1, isect.x()); + EXPECT_DOUBLE_EQ(0, isect.y()); + } + + // Incident + { + Vec2d p1(1, 0); Vec2d p2(3, 0); + Vec2d p3(2, 0); Vec2d p4(4, 0); + Vec2d isect(0, 0); + EXPECT_TRUE(PrimitiveTests::intersectLines(p1, p2, p3, p4, &isect)); + EXPECT_DOUBLE_EQ(2, isect.x()); + EXPECT_DOUBLE_EQ(0, isect.y()); + } + + // Parallell + { + Vec2d p1(0, 0); Vec2d p2(2, 0); + Vec2d p3(0, 2); Vec2d p4(2, 2); + Vec2d isect(0, 0); + EXPECT_FALSE(PrimitiveTests::intersectLines(p1, p2, p3, p4, &isect)); + EXPECT_DOUBLE_EQ(0, isect.x()); + EXPECT_DOUBLE_EQ(0, isect.y()); + } +} + diff --git a/Fwk/VizFwk/Tests/LibViewing_UnitTests/cvfModelBasicList-Test.cpp b/Fwk/VizFwk/Tests/LibViewing_UnitTests/cvfModelBasicList-Test.cpp index 9fe95c1504..9fe362f5f5 100644 --- a/Fwk/VizFwk/Tests/LibViewing_UnitTests/cvfModelBasicList-Test.cpp +++ b/Fwk/VizFwk/Tests/LibViewing_UnitTests/cvfModelBasicList-Test.cpp @@ -128,6 +128,51 @@ TEST(ModelBasicListDeathTest, IllegalIndexing) } #endif + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(ModelBasicListTest, shrinkPartCount) +{ + ref p1 = new Part; + ref p2 = new Part; + ref p3 = new Part; + + { + ref myModel = new ModelBasicList; + myModel->addPart(p1.p()); + myModel->addPart(p2.p()); + myModel->addPart(p3.p()); + ASSERT_EQ(3, myModel->partCount()); + EXPECT_EQ(2, p1->refCount()); + EXPECT_EQ(2, p2->refCount()); + EXPECT_EQ(2, p3->refCount()); + + myModel->shrinkPartCount(3); + ASSERT_EQ(3, myModel->partCount()); + EXPECT_EQ(2, p1->refCount()); + EXPECT_EQ(2, p2->refCount()); + EXPECT_EQ(2, p3->refCount()); + + myModel->shrinkPartCount(2); + ASSERT_EQ(2, myModel->partCount()); + EXPECT_EQ(2, p1->refCount()); + EXPECT_EQ(2, p2->refCount()); + EXPECT_EQ(1, p3->refCount()); + + myModel->shrinkPartCount(0); + ASSERT_EQ(0, myModel->partCount()); + EXPECT_EQ(1, p1->refCount()); + EXPECT_EQ(1, p2->refCount()); + EXPECT_EQ(1, p3->refCount()); + } + + EXPECT_EQ(1, p1->refCount()); + EXPECT_EQ(1, p2->refCount()); + EXPECT_EQ(1, p3->refCount()); +} + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/VizFwk/Tests/SnippetsBasis/snipVertexColoring.cpp b/Fwk/VizFwk/Tests/SnippetsBasis/snipVertexColoring.cpp index 74a0a13171..51d4c2ffb3 100644 --- a/Fwk/VizFwk/Tests/SnippetsBasis/snipVertexColoring.cpp +++ b/Fwk/VizFwk/Tests/SnippetsBasis/snipVertexColoring.cpp @@ -47,6 +47,16 @@ namespace snip { + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +VertexColoring::VertexColoring() +: m_useShaders(false) +{ +} + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -54,20 +64,37 @@ bool VertexColoring::onInitialize() { ref myModel = new ModelBasicList; - // Create the effect + // Create the fixed function effect { - m_effect = new Effect; + m_fixedFuncEffect = new Effect; ref mat = new RenderStateMaterial_FF(Color3::BLUE); mat->enableColorMaterial(true); - m_effect->setRenderState(mat.p()); + m_fixedFuncEffect->setRenderState(mat.p()); ref lighting = new RenderStateLighting_FF; - m_effect->setRenderState(lighting.p()); + m_fixedFuncEffect->setRenderState(lighting.p()); + } + + // Create effect with shader program + { + m_shaderEffect = new Effect; + + ShaderProgramGenerator gen("PerVertexColor", ShaderSourceProvider::instance()); + gen.addVertexCode(ShaderSourceRepository::vs_Standard); + gen.addFragmentCode(ShaderSourceRepository::src_VaryingColorGlobalAlpha); + gen.addFragmentCode(ShaderSourceRepository::light_SimpleHeadlight); + gen.addFragmentCode(ShaderSourceRepository::fs_Standard); + m_shaderProg = gen.generate(); + m_shaderProg->setDefaultUniform(new cvf::UniformFloat("u_alpha", 1.0f)); + + m_shaderEffect->setShaderProgram(m_shaderProg.p()); } - // "Normal" geometry + ref effectToUse = m_useShaders ? m_shaderEffect : m_fixedFuncEffect; + + // Lower left: "Normal" geometry { GeometryBuilderDrawableGeo builder; GeometryUtils::createBox(Vec3f(0,0,0), 2.0, 2.0, 2.0, &builder); @@ -76,12 +103,13 @@ bool VertexColoring::onInitialize() ref part = new Part; part->setDrawable(geo.p()); - part->setEffect(m_effect.p()); + part->setEffect(effectToUse.p()); myModel->addPart(part.p()); } - // Geometry with per vertex colors + // Lower right: Geometry with per vertex colors + // Results in one color per face of the cube { GeometryBuilderDrawableGeo builder; GeometryUtils::createBox(Vec3f(3,0,0), 2.0, 2.0, 2.0, &builder); @@ -114,12 +142,12 @@ bool VertexColoring::onInitialize() ref part = new Part; part->setDrawable(geo.p()); - part->setEffect(m_effect.p()); + part->setEffect(effectToUse.p()); myModel->addPart(part.p()); } - // Geometry with per vertex colors (using ScalarToColorMapper) + // Upper right: Geometry with per vertex colors (using ScalarToColorMapper) { BoxGenerator gen; gen.setMinMax(Vec3d(2,-1,2), Vec3d(4, 1, 4)); @@ -159,12 +187,12 @@ bool VertexColoring::onInitialize() ref part = new Part; part->setDrawable(geo.p()); - part->setEffect(m_effect.p()); + part->setEffect(effectToUse.p()); myModel->addPart(part.p()); } - // Geometry without normals + // Upper left: Geometry without normals { GeometryBuilderDrawableGeo builder; GeometryUtils::createBox(Vec3f(0,0,3), 2.0, 2.0, 2.0, &builder); @@ -173,7 +201,7 @@ bool VertexColoring::onInitialize() ref part = new Part; part->setDrawable(geo.p()); - part->setEffect(m_effect.p()); + part->setEffect(effectToUse.p()); myModel->addPart(part.p()); } @@ -233,11 +261,24 @@ void VertexColoring::onKeyPressEvent(KeyEvent* keyEvent) Key key = keyEvent->key(); char character = keyEvent->character(); + if (key == Key_S || key == Key_F) + { + m_useShaders = (key == Key_S) ? true : false; + + Collection partCollection; + m_renderSequence->firstRendering()->scene()->model(0)->allParts(&partCollection); + for (size_t i = 0; i < partCollection.size(); i++) + { + ref part = partCollection[i]; + part->setEffect(m_useShaders ? m_shaderEffect.p() : m_fixedFuncEffect.p()); + } + } + if (key == Key_L) { bool lightingOn = (character == 'l') ? true : false; - RenderStateLighting_FF* rsLighting = dynamic_cast(m_effect->renderStateOfType(RenderState::LIGHTING_FF)); + RenderStateLighting_FF* rsLighting = dynamic_cast(m_fixedFuncEffect->renderStateOfType(RenderState::LIGHTING_FF)); rsLighting->enable(lightingOn); } @@ -245,7 +286,7 @@ void VertexColoring::onKeyPressEvent(KeyEvent* keyEvent) { bool colorMaterialOn = (character == 'c') ? true : false; - RenderStateMaterial_FF* rsMaterial = dynamic_cast(m_effect->renderStateOfType(RenderState::MATERIAL_FF)); + RenderStateMaterial_FF* rsMaterial = dynamic_cast(m_fixedFuncEffect->renderStateOfType(RenderState::MATERIAL_FF)); rsMaterial->enableColorMaterial(colorMaterialOn); } @@ -259,8 +300,10 @@ void VertexColoring::onKeyPressEvent(KeyEvent* keyEvent) std::vector VertexColoring::helpText() const { std::vector help; - help.push_back(String("l/L - to toggle lighting on/off")); - help.push_back(String("c/C - to toggle color material on/off")); + help.push_back("s - to use a shader program for rendering"); + help.push_back("f - to use fixed function pipeline for rendering"); + help.push_back("l/L - to toggle lighting on/off (in fixed function)"); + help.push_back("c/C - to toggle color material on/off (in fixed function)"); return help; diff --git a/Fwk/VizFwk/Tests/SnippetsBasis/snipVertexColoring.h b/Fwk/VizFwk/Tests/SnippetsBasis/snipVertexColoring.h index 12fd16b1df..7e310d59f7 100644 --- a/Fwk/VizFwk/Tests/SnippetsBasis/snipVertexColoring.h +++ b/Fwk/VizFwk/Tests/SnippetsBasis/snipVertexColoring.h @@ -55,6 +55,7 @@ class VertexColoring : public TestSnippet CVFU_DECLARE_SNIPPET("Vertex Coloring"); public: + VertexColoring(); virtual bool onInitialize(); virtual void onKeyPressEvent(KeyEvent* keyEvent); @@ -64,7 +65,10 @@ class VertexColoring : public TestSnippet void addEdgesRendering(); private: - ref m_effect; + bool m_useShaders; + ref m_shaderProg; + ref m_fixedFuncEffect; + ref m_shaderEffect; }; } diff --git a/OctavePlugin/CMakeLists.txt b/OctavePlugin/CMakeLists.txt index 68a4b588d3..3a017e61de 100644 --- a/OctavePlugin/CMakeLists.txt +++ b/OctavePlugin/CMakeLists.txt @@ -4,28 +4,28 @@ # See http://www.cmake.org/Wiki/CMakeUserFindOctave set(CPP_SOURCES - riGetActiveCellProperty.cpp - riSetActiveCellProperty.cpp - riGetActiveCellInfo.cpp - riGetMainGridDimensions.cpp - riGetCurrentCase.cpp - riGetCaseGroups.cpp - riGetSelectedCases.cpp - riGetCases.cpp - riGetTimeStepDates.cpp - riGetTimeStepDays.cpp - riGetGridDimensions.cpp - riGetCoarseningInfo.cpp - riGetCellCenters.cpp - riGetActiveCellCenters.cpp - riGetCellCorners.cpp - riGetActiveCellCorners.cpp - riGetGridProperty.cpp - riSetGridProperty.cpp - riGetPropertyNames.cpp - riGetWellNames.cpp - riGetWellStatus.cpp - riGetWellCells.cpp + riGetActiveCellProperty.cpp + riSetActiveCellProperty.cpp + riGetActiveCellInfo.cpp + riGetMainGridDimensions.cpp + riGetCurrentCase.cpp + riGetCaseGroups.cpp + riGetSelectedCases.cpp + riGetCases.cpp + riGetTimeStepDates.cpp + riGetTimeStepDays.cpp + riGetGridDimensions.cpp + riGetCoarseningInfo.cpp + riGetCellCenters.cpp + riGetActiveCellCenters.cpp + riGetCellCorners.cpp + riGetActiveCellCorners.cpp + riGetGridProperty.cpp + riSetGridProperty.cpp + riGetPropertyNames.cpp + riGetWellNames.cpp + riGetWellStatus.cpp + riGetWellCells.cpp ) if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") @@ -51,18 +51,28 @@ else() message(WARNING "Failed to find mkoctfile, no Octave plugins will be compiled. Please specify RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE") endif() -find_program(RESINSIGHT_OCTAVE_PLUGIN_QMAKE NAMES qmake-qt4 qmake) + +set(RESINSIGHT_OCTAVE_PLUGIN_QMAKE "" CACHE FILEPATH "Location of custom qmake to be able to use a different Qt when compiling Octave plugins") if(RESINSIGHT_OCTAVE_PLUGIN_QMAKE) get_filename_component(OCTAVE_QMAKE_DIR ${RESINSIGHT_OCTAVE_PLUGIN_QMAKE} PATH) STRING(REPLACE "/bin" "" OCTAVE_QT_ROOT ${OCTAVE_QMAKE_DIR}) + message("Compiling Octave plugins using custom Qt located at ${OCTAVE_QT_ROOT}") + SET(OCTAVE_QT_INCLUDE_DIR ${OCTAVE_QT_ROOT}/include) SET(OCTAVE_QT_QTCORE_INCLUDE_DIR ${OCTAVE_QT_ROOT}/include/QtCore) SET(OCTAVE_QT_QTNETWORK_INCLUDE_DIR ${OCTAVE_QT_ROOT}/include/QtNetwork) SET(OCTAVE_QT_LIBRARY_DIR ${OCTAVE_QT_ROOT}/lib) else() - message(WARNING "Failed to find Qt to be used to compile Octave plugins, no Octave plugins will be compiled. Please specify RESINSIGHT_OCTAVE_PLUGIN_QMAKE") + set (RESINSIGHT_OCTAVE_PLUGIN_QMAKE ${QT_QMAKE_EXECUTABLE}) + + message("Compiling Octave plugins using system Qt - include path located at ${RESINSIGHT_OCTAVE_PLUGIN_QMAKE}") + + SET(OCTAVE_QT_INCLUDE_DIR ${QT_INCLUDE_DIR}) + SET(OCTAVE_QT_QTCORE_INCLUDE_DIR ${QT_QTCORE_INCLUDE_DIR}) + SET(OCTAVE_QT_QTNETWORK_INCLUDE_DIR ${QT_QTNETWORK_INCLUDE_DIR}) + SET(OCTAVE_QT_LIBRARY_DIR ${QT_LIBRARY_DIR}) endif() @@ -88,7 +98,7 @@ if (RESINSIGHT_OCTAVE_PLUGIN_QMAKE AND RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE) OUTPUT "${octFileName}" COMMAND call "\"%VS100COMNTOOLS%../../VC/vcvarsall.bat\"" x86 COMMAND ${CMAKE_COMMAND} ARGS -E chdir ${RESINSIGHT_OCTAVE_BIN_DIR} ${RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE} -I${OCTAVE_QT_QTNETWORK_INCLUDE_DIR} - -I${OCTAVE_QT_QTCORE_INCLUDE_DIR} -I${OCTAVE_QT_INCLUDE_DIR} ${RPATH_COMMAND} + -I${OCTAVE_QT_QTCORE_INCLUDE_DIR} -I${OCTAVE_QT_INCLUDE_DIR} -I${ResInsight_SOURCE_DIR}/ApplicationCode/SocketInterface ${RPATH_COMMAND} -L${OCTAVE_QT_LIBRARY_DIR} -lQtCore${QT_LIBRARY_POSTFIX} -lQtNetwork${QT_LIBRARY_POSTFIX} -o "${octFileName}" "${srcFileName}" DEPENDS "${srcFileName}" COMMENT "===> 32-bit x86 VS2010 : Generating ${octFileName}" @@ -97,7 +107,7 @@ if (RESINSIGHT_OCTAVE_PLUGIN_QMAKE AND RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE) add_custom_command( OUTPUT "${octFileName}" COMMAND ${CMAKE_COMMAND} ARGS -E chdir ${RESINSIGHT_OCTAVE_BIN_DIR} ${RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE} -I${OCTAVE_QT_QTNETWORK_INCLUDE_DIR} - -I${OCTAVE_QT_QTCORE_INCLUDE_DIR} -I${OCTAVE_QT_INCLUDE_DIR} ${RPATH_COMMAND} + -I${OCTAVE_QT_QTCORE_INCLUDE_DIR} -I${OCTAVE_QT_INCLUDE_DIR} -I${ResInsight_SOURCE_DIR}/ApplicationCode/SocketInterface ${RPATH_COMMAND} -L${OCTAVE_QT_LIBRARY_DIR} -lQtCore${QT_LIBRARY_POSTFIX} -lQtNetwork${QT_LIBRARY_POSTFIX} -o "${octFileName}" "${srcFileName}" DEPENDS "${srcFileName}" COMMENT "===> Generating ${octFileName}" @@ -107,7 +117,7 @@ if (RESINSIGHT_OCTAVE_PLUGIN_QMAKE AND RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE) add_custom_command( OUTPUT "${octFileName}" COMMAND OCTAVE_HOME=${OCTAVE_HOME} ${RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE} - -I${OCTAVE_QT_QTNETWORK_INCLUDE_DIR} -I${OCTAVE_QT_QTCORE_INCLUDE_DIR} -I${OCTAVE_QT_INCLUDE_DIR} ${RPATH_COMMAND} + -I${OCTAVE_QT_QTNETWORK_INCLUDE_DIR} -I${OCTAVE_QT_QTCORE_INCLUDE_DIR} -I${OCTAVE_QT_INCLUDE_DIR} -I${ResInsight_SOURCE_DIR}/ApplicationCode/SocketInterface ${RPATH_COMMAND} -L${OCTAVE_QT_LIBRARY_DIR} -lQtCore -lQtNetwork -o "${octFileName}" "${srcFileName}" DEPENDS "${srcFileName}" COMMENT "===> Generating ${octFileName}" @@ -141,7 +151,9 @@ if (RESINSIGHT_OCTAVE_PLUGIN_QMAKE AND RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE) "${CMAKE_CURRENT_BINARY_DIR}/riGetWellNames.oct" "${CMAKE_CURRENT_BINARY_DIR}/riGetWellStatus.oct" "${CMAKE_CURRENT_BINARY_DIR}/riGetWellCells.oct" - SOURCES ${CPP_SOURCES} + SOURCES + ${CPP_SOURCES} + riSettings.h ) diff --git a/OctavePlugin/OctaveScripts/kslice.m b/OctavePlugin/OctaveScripts/kslice.m index 4049e6c80d..a0f8cc5141 100644 --- a/OctavePlugin/OctaveScripts/kslice.m +++ b/OctavePlugin/OctaveScripts/kslice.m @@ -1,4 +1,4 @@ -addpath("/home/builder/Projects/ResInsightBuildDir/OctavePlugin"); + CInfo = riGetActiveCellInfo(); SOIL = riGetActiveCellProperty("SOIL"); diff --git a/OctavePlugin/riGetActiveCellCenters.cpp b/OctavePlugin/riGetActiveCellCenters.cpp index 90c1631f30..862172ba0a 100644 --- a/OctavePlugin/riGetActiveCellCenters.cpp +++ b/OctavePlugin/riGetActiveCellCenters.cpp @@ -1,7 +1,10 @@ #include +#include + #include #include "riSettings.h" +#include "RiaSocketDataTransfer.cpp" // NB! Include cpp-file to avoid linking of additional file in oct-compile configuration void getActiveCellCenters(NDArray& cellCenterValues, const QString &hostName, quint16 port, const qint32& caseId, const QString& porosityModel) @@ -61,24 +64,17 @@ void getActiveCellCenters(NDArray& cellCenterValues, const QString &hostName, qu cellCenterValues.resize(dv); - while (socket.bytesAvailable() < (qint64)(byteCount)) + double* internalMatrixData = cellCenterValues.fortran_vec(); + QStringList errorMessages; + + if (!RiaSocketDataTransfer::readBlockDataFromSocket(&socket, (char*)(internalMatrixData), byteCount, errorMessages)) { - if (!socket.waitForReadyRead(riOctavePlugin::longTimeOutMilliSecs)) + for (int i = 0; i < errorMessages.size(); i++) { - error((("Waiting for data: ") + socket.errorString()).toLatin1().data()); - return; + error(errorMessages[i].toLatin1().data()); } - OCTAVE_QUIT; - } - - quint64 bytesRead = 0; - double* internalMatrixData = cellCenterValues.fortran_vec(); - bytesRead = socket.read((char*)(internalMatrixData), byteCount); - if (byteCount != bytesRead) - { - error("Could not read binary double data properly from socket"); - octave_stdout << "Active cell count: " << activeCellCount << std::endl; + OCTAVE_QUIT; } return; diff --git a/OctavePlugin/riGetActiveCellCorners.cpp b/OctavePlugin/riGetActiveCellCorners.cpp index 6fb285cc4a..d018310285 100644 --- a/OctavePlugin/riGetActiveCellCorners.cpp +++ b/OctavePlugin/riGetActiveCellCorners.cpp @@ -1,7 +1,10 @@ #include +#include + #include #include "riSettings.h" +#include "RiaSocketDataTransfer.cpp" // NB! Include cpp-file to avoid linking of additional file in oct-compile configuration void getActiveCellCorners(NDArray& cellCornerValues, const QString &hostName, quint16 port, const qint32& caseId, const QString& porosityModel) @@ -61,24 +64,16 @@ void getActiveCellCorners(NDArray& cellCornerValues, const QString &hostName, qu dv(2) = 3; cellCornerValues.resize(dv); - while (socket.bytesAvailable() < (qint64)(byteCount)) + double* internalMatrixData = cellCornerValues.fortran_vec(); + QStringList errorMessages; + if (!RiaSocketDataTransfer::readBlockDataFromSocket(&socket, (char*)(internalMatrixData), byteCount, errorMessages)) { - if (!socket.waitForReadyRead(riOctavePlugin::longTimeOutMilliSecs)) + for (int i = 0; i < errorMessages.size(); i++) { - error((("Waiting for data: ") + socket.errorString()).toLatin1().data()); - return; + error(errorMessages[i].toLatin1().data()); } - OCTAVE_QUIT; - } - - quint64 bytesRead = 0; - double* internalMatrixData = cellCornerValues.fortran_vec(); - bytesRead = socket.read((char*)(internalMatrixData), byteCount); - if (byteCount != bytesRead) - { - error("Could not read binary double data properly from socket"); - octave_stdout << "Active cell count: " << activeCellCount << std::endl; + OCTAVE_QUIT; } return; diff --git a/OctavePlugin/riGetActiveCellInfo.cpp b/OctavePlugin/riGetActiveCellInfo.cpp index 824134e0f7..8a9f4bc8eb 100644 --- a/OctavePlugin/riGetActiveCellInfo.cpp +++ b/OctavePlugin/riGetActiveCellInfo.cpp @@ -1,8 +1,9 @@ #include -#include +#include +#include #include "riSettings.h" - +#include "RiaSocketDataTransfer.cpp" // NB! Include cpp-file to avoid linking of additional file in oct-compile configuration void getActiveCellInfo(int32NDArray& activeCellInfo, const QString &hostName, quint16 port, const qint64& caseId, const QString& porosityModel) { @@ -43,59 +44,32 @@ void getActiveCellInfo(int32NDArray& activeCellInfo, const QString &hostName, qu // Read timestep count and blocksize quint64 columnCount; - quint64 byteCount; + quint64 byteCountForOneTimestep; size_t activeCellCount; socketStream >> columnCount; - socketStream >> byteCount; + socketStream >> byteCountForOneTimestep; - activeCellCount = byteCount / sizeof(qint32); + activeCellCount = byteCountForOneTimestep / sizeof(qint32); dim_vector dv (2, 1); dv(0) = activeCellCount; dv(1) = columnCount; activeCellInfo.resize(dv); - if (!(byteCount && columnCount)) + if (!(byteCountForOneTimestep && columnCount)) { error ("Could not find the requested data in ResInsight"); return; } - // Wait for available data for each column, then read data for each column - for (size_t tIdx = 0; tIdx < columnCount; ++tIdx) + qint32* internalMatrixData = (qint32*)activeCellInfo.fortran_vec()->mex_get_data(); + QStringList errorMessages; + if (!RiaSocketDataTransfer::readBlockDataFromSocket(&socket, (char*)(internalMatrixData), columnCount * byteCountForOneTimestep, errorMessages)) { - while (socket.bytesAvailable() < (int)byteCount) - { - if (!socket.waitForReadyRead(riOctavePlugin::longTimeOutMilliSecs)) - { - QString errorMsg = QString("Waiting for column number: %1 of %2: %3").arg(tIdx).arg(columnCount).arg(socket.errorString()); - - error(errorMsg.toLatin1().data()); - octave_stdout << "Active cells: " << activeCellCount << ", Columns: " << columnCount << std::endl; - return ; - } - OCTAVE_QUIT; - } - - qint64 bytesRead = 0; - qint32* internalMatrixData = (qint32*)activeCellInfo.fortran_vec()->mex_get_data(); - -#if 1 // Use raw data transfer. Faster. - bytesRead = socket.read((char*)(internalMatrixData + tIdx * activeCellCount), byteCount); -#else - for (size_t cIdx = 0; cIdx < activeCellCount; ++cIdx) - { - socketStream >> internalMatrixData[tIdx * activeCellCount + cIdx]; - - if (socketStream.status() == QDataStream::Ok) bytesRead += sizeof(int); - } -#endif - - if ((int)byteCount != bytesRead) + for (int i = 0; i < errorMessages.size(); i++) { - error("Could not read binary double data properly from socket"); - octave_stdout << "Active cells: " << activeCellCount << ", Columns: " << columnCount << std::endl; + error(errorMessages[i].toLatin1().data()); } OCTAVE_QUIT; diff --git a/OctavePlugin/riGetActiveCellProperty.cpp b/OctavePlugin/riGetActiveCellProperty.cpp index a936b82d96..573e324f12 100644 --- a/OctavePlugin/riGetActiveCellProperty.cpp +++ b/OctavePlugin/riGetActiveCellProperty.cpp @@ -1,7 +1,12 @@ #include +#include + #include + #include "riSettings.h" +#include "RiaSocketDataTransfer.cpp" // NB! Include cpp-file to avoid linking of additional file in oct-compile configuration + void getActiveCellProperty(Matrix& propertyFrames, const QString &serverName, quint16 serverPort, const qint64& caseId, QString propertyName, const int32NDArray& requestedTimeSteps, QString porosityModel) { @@ -63,44 +68,18 @@ void getActiveCellProperty(Matrix& propertyFrames, const QString &serverName, qu return; } - // Wait for available data for each timestep, then read data for each timestep + quint64 totalByteCount = byteCount * timestepCount; - for (size_t tIdx = 0; tIdx < timestepCount; ++tIdx) + double* internalMatrixData = propertyFrames.fortran_vec(); + QStringList errorMessages; + if (!RiaSocketDataTransfer::readBlockDataFromSocket(&socket, (char*)(internalMatrixData), totalByteCount, errorMessages)) { - while (socket.bytesAvailable() < (int)byteCount) - { - if (!socket.waitForReadyRead(riOctavePlugin::longTimeOutMilliSecs)) - { - error((("Waiting for timestep data number: ") + QString::number(tIdx)+ ": " + socket.errorString()).toLatin1().data()); - octave_stdout << "Active cells: " << activeCellCount << ", Timesteps: " << timestepCount << std::endl; - return ; - } - OCTAVE_QUIT; - } - - qint64 bytesRead = 0; - double * internalMatrixData = propertyFrames.fortran_vec(); - -#if 0 - // Raw data transfer. Faster. Not possible when dealing with coarsening - // bytesRead = socket.read((char*)(internalMatrixData + tIdx * activeCellCount), byteCount); -#else - // Compatible transfer. Now the only one working - for (size_t cIdx = 0; cIdx < activeCellCount; ++cIdx) - { - socketStream >> internalMatrixData[tIdx * activeCellCount + cIdx]; - - if (socketStream.status() == QDataStream::Ok) bytesRead += sizeof(double); - } -#endif - - if ((int)byteCount != bytesRead) + for (int i = 0; i < errorMessages.size(); i++) { - error("Could not read binary double data properly from socket"); - octave_stdout << "Active cells: " << activeCellCount << ", Timesteps: " << timestepCount << std::endl; + error(errorMessages[i].toLatin1().data()); } - OCTAVE_QUIT; + return; } QString tmp = QString("riGetActiveCellProperty : Read %1").arg(propertyName); diff --git a/OctavePlugin/riGetCellCenters.cpp b/OctavePlugin/riGetCellCenters.cpp index cb65de3d01..a8255b6fb5 100644 --- a/OctavePlugin/riGetCellCenters.cpp +++ b/OctavePlugin/riGetCellCenters.cpp @@ -1,7 +1,10 @@ #include +#include + #include #include "riSettings.h" +#include "RiaSocketDataTransfer.cpp" // NB! Include cpp-file to avoid linking of additional file in oct-compile configuration void getCellCenters(NDArray& cellCenterValues, const QString &hostName, quint16 port, const qint32& caseId, const quint32& gridIndex) @@ -66,39 +69,18 @@ void getCellCenters(NDArray& cellCenterValues, const QString &hostName, quint16 dv(3) = 3; cellCenterValues.resize(dv); - while (socket.bytesAvailable() < (qint64)(byteCount)) + double* internalMatrixData = cellCenterValues.fortran_vec(); + QStringList errorMessages; + if (!RiaSocketDataTransfer::readBlockDataFromSocket(&socket, (char*)(internalMatrixData), byteCount, errorMessages)) { - if (!socket.waitForReadyRead(riOctavePlugin::longTimeOutMilliSecs)) + for (int i = 0; i < errorMessages.size(); i++) { - error((("Waiting for data: ") + socket.errorString()).toLatin1().data()); - return; + error(errorMessages[i].toLatin1().data()); } - OCTAVE_QUIT; - } - - //octave_stdout << " riGetCellCenters : I = " << cellCountI <<" J = " << cellCountJ << " K = " << cellCountK << std::endl; - //octave_stdout << " riGetCellCenters : numDoubles = " << valueCount << std::endl; - double* internalMatrixData = cellCenterValues.fortran_vec(); - -#if 0 - octave_idx_type valueCount = cellCenterValues.length(); - double val; - for (octave_idx_type i = 0; i < valueCount; i++) - { - socketStream >> internalMatrixData[i]; - } -#else - quint64 bytesRead = 0; - bytesRead = socket.read((char*)(internalMatrixData), byteCount); - - if (byteCount != bytesRead) - { - error("Could not read binary double data properly from socket"); - octave_stdout << "Cell count: " << cellCount << std::endl; + OCTAVE_QUIT; } -#endif return; } diff --git a/OctavePlugin/riGetCellCorners.cpp b/OctavePlugin/riGetCellCorners.cpp index ee8f810239..2ed5d264b9 100644 --- a/OctavePlugin/riGetCellCorners.cpp +++ b/OctavePlugin/riGetCellCorners.cpp @@ -1,7 +1,12 @@ #include +#include + #include #include "riSettings.h" +#include "RiaSocketDataTransfer.cpp" // NB! Include cpp-file to avoid linking of additional file in oct-compile configuration + + void getCellCorners(NDArray& cellCornerValues, const QString &hostName, quint16 port, const qint32& caseId, const quint32& gridIndex) @@ -67,37 +72,18 @@ void getCellCorners(NDArray& cellCornerValues, const QString &hostName, quint16 dv(4) = 3; cellCornerValues.resize(dv); - - while (socket.bytesAvailable() < (qint64)(byteCount)) + double* internalMatrixData = cellCornerValues.fortran_vec(); + QStringList errorMessages; + if (!RiaSocketDataTransfer::readBlockDataFromSocket(&socket, (char*)(internalMatrixData), byteCount, errorMessages)) { - if (!socket.waitForReadyRead(riOctavePlugin::longTimeOutMilliSecs)) + for (int i = 0; i < errorMessages.size(); i++) { - error((("Waiting for data: ") + socket.errorString()).toLatin1().data()); - return; + error(errorMessages[i].toLatin1().data()); } - OCTAVE_QUIT; - } - double* internalMatrixData = cellCornerValues.fortran_vec(); - -#if 0 - double val; - for (octave_idx_type i = 0; i < valueCount; i++) - { - socketStream >> internalMatrixData[i]; - } -#else - quint64 bytesRead = 0; - bytesRead = socket.read((char*)(internalMatrixData), byteCount); - - if (byteCount != bytesRead) - { - error("Could not read binary double data properly from socket"); - octave_stdout << "Cell count: " << cellCount << std::endl; + OCTAVE_QUIT; } -#endif - return; } diff --git a/OctavePlugin/riGetGridProperty.cpp b/OctavePlugin/riGetGridProperty.cpp index 3771341644..075c36ee48 100644 --- a/OctavePlugin/riGetGridProperty.cpp +++ b/OctavePlugin/riGetGridProperty.cpp @@ -1,6 +1,11 @@ #include +#include + #include + #include "riSettings.h" +#include "RiaSocketDataTransfer.cpp" // NB! Include cpp-file to avoid linking of additional file in oct-compile configuration + void getGridProperty(NDArray& propertyFrames, const QString &serverName, quint16 serverPort, const int& caseId, int gridIdx, QString propertyName, const int32NDArray& requestedTimeSteps, QString porosityModel) @@ -22,7 +27,7 @@ void getGridProperty(NDArray& propertyFrames, const QString &serverName, quint16 QString command; command += "GetGridProperty " + QString::number(caseId) + " " + QString::number(gridIdx) + " " + propertyName + " " + porosityModel; - for (int i = 0; i < requestedTimeSteps.length(); ++i) + for (qint64 i = 0; i < requestedTimeSteps.length(); ++i) { if (i == 0) command += " "; command += QString::number(static_cast(requestedTimeSteps.elem(i)) - 1); // To make the index 0-based @@ -36,7 +41,7 @@ void getGridProperty(NDArray& propertyFrames, const QString &serverName, quint16 // Get response. First wait for the header - while (socket.bytesAvailable() < (int)(4*sizeof(quint64))) + while (socket.bytesAvailable() < (qint64)(4*sizeof(quint64))) { if (!socket.waitForReadyRead(riOctavePlugin::longTimeOutMilliSecs)) { @@ -48,6 +53,7 @@ void getGridProperty(NDArray& propertyFrames, const QString &serverName, quint16 // Read sizes quint64 totalByteCount; + quint64 cellCountI; quint64 cellCountJ; quint64 cellCountK; @@ -59,6 +65,7 @@ void getGridProperty(NDArray& propertyFrames, const QString &serverName, quint16 socketStream >> timestepCount; totalByteCount = cellCountI*cellCountJ*cellCountK*timestepCount*sizeof(double); + if (!(totalByteCount)) { error ("Could not find the requested data in ResInsight"); @@ -74,28 +81,16 @@ void getGridProperty(NDArray& propertyFrames, const QString &serverName, quint16 propertyFrames.resize(dv); - - // Wait for available data - - while (socket.bytesAvailable() < (int)totalByteCount) + double* internalMatrixData = propertyFrames.fortran_vec(); + QStringList errorMessages; + if (!RiaSocketDataTransfer::readBlockDataFromSocket(&socket, (char*)(internalMatrixData), totalByteCount, errorMessages)) { - if (!socket.waitForReadyRead(riOctavePlugin::longTimeOutMilliSecs)) + for (int i = 0; i < errorMessages.size(); i++) { - error(("Waiting for data : " + socket.errorString()).toLatin1().data()); - return ; + error(errorMessages[i].toLatin1().data()); } - OCTAVE_QUIT; - } - - qint64 bytesRead = 0; - double * internalMatrixData = propertyFrames.fortran_vec(); - - // Raw data transfer. Faster. - bytesRead = socket.read((char*)(internalMatrixData ), totalByteCount); - if ((int)totalByteCount != bytesRead) - { - error("Could not read binary double data properly from socket"); + return; } QString tmp = QString("riGetGridProperty : Read %1").arg(propertyName); diff --git a/OctavePlugin/riSetActiveCellProperty.cpp b/OctavePlugin/riSetActiveCellProperty.cpp index 4953f25778..a079ccd0da 100644 --- a/OctavePlugin/riSetActiveCellProperty.cpp +++ b/OctavePlugin/riSetActiveCellProperty.cpp @@ -1,6 +1,10 @@ #include +#include + #include + #include "riSettings.h" +#include "RiaSocketDataTransfer.cpp" // NB! Include cpp-file to avoid linking of additional file in oct-compile configuration void setEclipseProperty(const Matrix& propertyFrames, const QString &hostName, quint16 port, @@ -47,35 +51,39 @@ void setEclipseProperty(const Matrix& propertyFrames, const QString &hostName, q socketStream << (qint64)timeStepByteCount; const double* internalData = propertyFrames.fortran_vec(); - qint64 dataWritten = socket.write((const char *)internalData, timeStepByteCount*timeStepCount); - if (dataWritten == timeStepByteCount*timeStepCount) + QStringList errorMessages; + if (!RiaSocketDataTransfer::writeBlockDataToSocket(&socket, (const char *)internalData, timeStepByteCount*timeStepCount, errorMessages)) { - QString tmp = QString("riSetActiveCellProperty : Wrote %1").arg(propertyName); - - if (caseId == -1) + for (int i = 0; i < errorMessages.size(); i++) { - tmp += QString(" to current case."); + octave_stdout << errorMessages[i].toStdString(); } - else - { - tmp += QString(" to case with Id = %1.").arg(caseId); - } - octave_stdout << tmp.toStdString() << " Active Cells : " << cellCount << " Time steps : " << timeStepCount << std::endl; + + return; + } + + QString tmp = QString("riSetActiveCellProperty : Wrote %1").arg(propertyName); + + if (caseId == -1) + { + tmp += QString(" to current case."); } else { - error("riSetActiveCellProperty : Was not able to write the proper amount of data to ResInsight:"); - octave_stdout << " Active Cells : " << cellCount << "Time steps : " << timeStepCount << " Data Written: " << dataWritten << " Should have written: " << timeStepCount * cellCount * sizeof(double) << std::endl; + tmp += QString(" to case with Id = %1.").arg(caseId); } + octave_stdout << tmp.toStdString() << " Active Cells : " << cellCount << " Time steps : " << timeStepCount << std::endl; while(socket.bytesToWrite() && socket.state() == QAbstractSocket::ConnectedState) { // octave_stdout << "Bytes to write: " << socket.bytesToWrite() << std::endl; - socket.waitForBytesWritten(riOctavePlugin::longTimeOutMilliSecs); + socket.waitForBytesWritten(riOctavePlugin::shortTimeOutMilliSecs); OCTAVE_QUIT; } + //octave_stdout << " Socket write completed" << std::endl; + if (socket.bytesToWrite() && socket.state() != QAbstractSocket::ConnectedState) { error("riSetActiveCellProperty : ResInsight refused to accept the data. Maybe the dimensions or porosity model is wrong"); diff --git a/OctavePlugin/riSetGridProperty.cpp b/OctavePlugin/riSetGridProperty.cpp index 04773e8804..3ef34adda4 100644 --- a/OctavePlugin/riSetGridProperty.cpp +++ b/OctavePlugin/riSetGridProperty.cpp @@ -1,6 +1,10 @@ #include +#include + #include + #include "riSettings.h" +#include "RiaSocketDataTransfer.cpp" // NB! Include cpp-file to avoid linking of additional file in oct-compile configuration void setEclipseProperty(const NDArray& propertyFrames, const QString &hostName, quint16 port, @@ -64,36 +68,41 @@ void setEclipseProperty(const NDArray& propertyFrames, const QString &hostName, socketStream << (qint64)singleTimeStepByteCount; const double* internalData = propertyFrames.fortran_vec(); - int dataWritten = socket.write((const char *)internalData, singleTimeStepByteCount*timeStepCount); - if (dataWritten == singleTimeStepByteCount*timeStepCount) + QStringList errorMessages; + if (!RiaSocketDataTransfer::writeBlockDataToSocket(&socket, (const char *)internalData, timeStepCount*singleTimeStepByteCount, errorMessages)) { - QString tmp = QString("riSetGridProperty : Wrote %1").arg(propertyName); - - if (caseId == -1) - { - tmp += QString(" to current case,"); - } - else + for (int i = 0; i < errorMessages.size(); i++) { - tmp += QString(" to case with Id = %1,").arg(caseId); + octave_stdout << errorMessages[i].toStdString(); } - - tmp += QString(" grid index: %1, ").arg(gridIndex); - octave_stdout << tmp.toStdString() << " Time steps : " << timeStepCount << std::endl; + size_t cellCount = cellCountI * cellCountJ * cellCountK; + error("riSetGridProperty : Was not able to write the proper amount of data to ResInsight:"); + octave_stdout << " Cell count : " << cellCount << "Time steps : " << timeStepCount << std::endl; + + return; + } + + QString tmp = QString("riSetGridProperty : Wrote %1").arg(propertyName); + + if (caseId == -1) + { + tmp += QString(" to current case,"); } else { - size_t cellCount = cellCountI * cellCountJ * cellCountK; - error("riSetGridProperty : Was not able to write the proper amount of data to ResInsight:"); - octave_stdout << " Cell count : " << cellCount << "Time steps : " << timeStepCount << " Data Written: " << dataWritten << " Should have written: " << timeStepCount * cellCount * sizeof(double) << std::endl; + tmp += QString(" to case with Id = %1,").arg(caseId); } + + tmp += QString(" grid index: %1, ").arg(gridIndex); + + octave_stdout << tmp.toStdString() << " Time steps : " << timeStepCount << std::endl; while(socket.bytesToWrite() && socket.state() == QAbstractSocket::ConnectedState) { - // octave_stdout << "Bytes to write: " << socket.bytesToWrite() << std::endl; - socket.waitForBytesWritten(riOctavePlugin::longTimeOutMilliSecs); +// octave_stdout << "Bytes to write: " << socket.bytesToWrite() << std::endl << std::flush; + socket.waitForBytesWritten(riOctavePlugin::shortTimeOutMilliSecs); OCTAVE_QUIT; } diff --git a/OctavePlugin/riSettings.h b/OctavePlugin/riSettings.h index bc7220e845..63ad778b37 100644 --- a/OctavePlugin/riSettings.h +++ b/OctavePlugin/riSettings.h @@ -21,9 +21,11 @@ namespace riOctavePlugin { const int connectTimeOutMilliSecs = 5000; - const int shortTimeOutMilliSecs = 5000; + const int shortTimeOutMilliSecs = 1000; const int longTimeOutMilliSecs = 6000000; + const int socketMaxByteCount = 100000; + // Octave data structure : CaseInfo char caseInfo_CaseId[] = "CaseId"; char caseInfo_CaseName[] = "CaseName"; diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index 4d253b33dc..69e4286f37 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,6 +1,6 @@ set(CMAKE_MAJOR_VERSION 1) -set(CMAKE_MINOR_VERSION 1) +set(CMAKE_MINOR_VERSION 2) set(CMAKE_PATCH_VERSION 0) set(PRODUCTVER ${CMAKE_MAJOR_VERSION},${CMAKE_MINOR_VERSION},0,${CMAKE_PATCH_VERSION})