Merge pull request #153 from OPM/dev

ResInsight 1.1.0
This commit is contained in:
Magne Sjaastad
2014-01-23 05:11:41 -08:00
1866 changed files with 531155 additions and 6248 deletions

32
.gitignore vendored
View File

@@ -33,3 +33,35 @@ CTest*.cmake
# Target program
/ApplicationCode/ResInsight
/.project
#Visual Studio files
*.[Oo]bj
*.user
*.aps
*.pch
*.vspscc
*.vssscc
*_i.c
*_p.c
*.ncb
*.suo
*.tlb
*.tlh
*.bak
*.[Cc]ache
*.ilk
*.log
*.lib
*.sbr
*.sdf
*.opensdf
*.unsuccessfulbuild
ipch/
[Oo]bj/
[Bb]in
[Dd]ebug*/
[Rr]elease*/
Ankh.NoLoad
#Temp files
*.temp

View File

@@ -48,6 +48,7 @@
#include "RimUiTreeModelPdm.h"
#include "RiaImageCompareReporter.h"
#include "RiaImageFileCompare.h"
#include "RiaProjectModifier.h"
#include "cafProgressInfo.h"
#include "RigGridManager.h"
@@ -72,8 +73,13 @@
#include "RimCellPropertyFilterCollection.h"
#include "Rim3dOverlayInfoConfig.h"
#include "RimWellCollection.h"
#include "RimStatisticsCase.h"
#include "cafCeetronPlusNavigation.h"
#include "cvfProgramOptions.h"
#include "cvfqtUtils.h"
namespace caf
{
template<>
@@ -98,6 +104,9 @@ namespace RegTestNames
};
//==================================================================================================
///
/// \class RiaApplication
@@ -240,10 +249,11 @@ const char* RiaApplication::getVersionStringApp(bool includeCrtInfo)
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RiaApplication::loadProject(const QString& projectFileName)
bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadAction loadAction, RiaProjectModifier* projectModifier)
{
// First Close the current project
@@ -257,6 +267,12 @@ bool RiaApplication::loadProject(const QString& projectFileName)
m_project->fileName = projectFileName;
m_project->readFile();
// Apply any modifiactions to the loaded project before we go ahead and load actual data
if (projectModifier)
{
projectModifier->applyModificationsToProject(m_project);
}
// Propagate possible new location of project
m_project->setProjectFileNameAndUpdateDependencies(projectFileName);
@@ -319,6 +335,23 @@ bool RiaApplication::loadProject(const QString& projectFileName)
if (oilField->wellPathCollection) oilField->wellPathCollection->readWellPathFiles();
}
// If load action is specified to recalculate statistics, do it now.
// Apparently this needs to be done before the views are loaded, lest the number of time steps for statistics will be clamped
if (loadAction & PLA_CALCULATE_STATISTICS)
{
for (size_t oilFieldIdx = 0; oilFieldIdx < m_project->oilFields().size(); oilFieldIdx++)
{
RimOilField* oilField = m_project->oilFields[oilFieldIdx];
RimAnalysisModels* analysisModels = oilField ? oilField->analysisModels() : NULL;
if (analysisModels)
{
analysisModels->recomputeStatisticsForAllCaseGroups();
}
}
}
// Now load the ReservoirViews for the cases
// Add all "native" cases in the project
std::vector<RimCase*> casesToLoad;
@@ -351,6 +384,8 @@ bool RiaApplication::loadProject(const QString& projectFileName)
caseProgress.incrementProgress();
}
// NB! This function must be called before executing command objects,
// because the tree view state is restored from project file and sets
// current active view ( see restoreTreeViewState() )
@@ -374,6 +409,15 @@ bool RiaApplication::loadProject(const QString& projectFileName)
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RiaApplication::loadProject(const QString& projectFileName)
{
return loadProject(projectFileName, PLA_NONE, NULL);
}
//--------------------------------------------------------------------------------------------------
/// Add a list of well path file paths (JSON files) to the well path collection
//--------------------------------------------------------------------------------------------------
@@ -398,15 +442,6 @@ void RiaApplication::addWellPathsToModel(QList<QString> wellPathFilePaths)
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RiaApplication::loadLastUsedProject()
{
return loadProject(m_preferences->lastUsedProjectFileName);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -544,6 +579,33 @@ QString RiaApplication::currentProjectFileName() const
}
//--------------------------------------------------------------------------------------------------
/// Create an absolute path from a path that is specified relative to the project directory
///
/// If the path specified in \a projectRelativePath is already absolute, no changes will be made
//--------------------------------------------------------------------------------------------------
QString RiaApplication::createAbsolutePathFromProjectRelativePath(QString projectRelativePath)
{
// Check if path is already absolute
if (QDir::isAbsolutePath(projectRelativePath))
{
return projectRelativePath;
}
if (m_project && !m_project->fileName().isEmpty())
{
QString absoluteProjectPath = QFileInfo(m_project->fileName()).absolutePath();
QDir projectDir(absoluteProjectPath);
return projectDir.absoluteFilePath(projectRelativePath);
}
else
{
return projectRelativePath;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -745,178 +807,187 @@ bool RiaApplication::showPerformanceInfo() const
//--------------------------------------------------------------------------------------------------
bool RiaApplication::parseArguments()
{
cvf::ProgramOptions progOpt;
progOpt.registerOption("last", "", "Open last used project.");
progOpt.registerOption("project", "<filename>", "Open project file <filename>.", cvf::ProgramOptions::SINGLE_VALUE);
progOpt.registerOption("case", "<casename>", "Import Eclipse case <casename> (do not include the .GRID/.EGRID extension.)", cvf::ProgramOptions::MULTI_VALUE);
progOpt.registerOption("startdir", "<folder>", "Set startup directory.", cvf::ProgramOptions::SINGLE_VALUE);
progOpt.registerOption("savesnapshots", "", "Save snapshot of all views to 'snapshots' folder. Application closes after snapshots have been written.");
progOpt.registerOption("size", "<width> <height>", "Set size of the main application window.", cvf::ProgramOptions::MULTI_VALUE);
progOpt.registerOption("replaceCase", "[<caseId>] <newGridFile>", "Replace grid in <caseId> or first case with <newgridFile>.", cvf::ProgramOptions::MULTI_VALUE);
progOpt.registerOption("replaceSourceCases", "[<caseGroupId>] <gridListFile>", "Replace source cases in <caseGroupId> or first grid case group with the grid files listed in the <gridListFile> file.", cvf::ProgramOptions::MULTI_VALUE);
progOpt.registerOption("multiCaseSnapshots", "<gridListFile>", "For each grid file listed in the <gridListFile> file, replace the first case in the project and save snapshot of all views.", cvf::ProgramOptions::SINGLE_VALUE);
progOpt.registerOption("help", "", "Displays help text.");
progOpt.registerOption("?", "", "Displays help text.");
progOpt.registerOption("regressiontest", "<folder>", "", cvf::ProgramOptions::SINGLE_VALUE);
progOpt.registerOption("updateregressiontestbase", "<folder>", "", cvf::ProgramOptions::SINGLE_VALUE);
progOpt.setOptionPrefix(cvf::ProgramOptions::DOUBLE_DASH);
m_helpText = QString("\n%1 v. %2\n").arg(RI_APPLICATION_NAME).arg(getVersionStringApp(false));
m_helpText += "Copyright Statoil ASA, Ceetron AS 2011, 2012\n\n";
const cvf::String usageText = progOpt.usageText(110, 30);
m_helpText += cvfqt::Utils::toQString(usageText);
QStringList arguments = QCoreApplication::arguments();
bool openLatestProject = false;
QString projectFilename;
QStringList caseNames;
QString regressionTestPath;
bool parseOk = progOpt.parse(cvfqt::Utils::toStringVector(arguments));
enum ArgumentParsingType
if (!parseOk || progOpt.hasOption("help") || progOpt.hasOption("?"))
{
PARSE_PROJECT_FILE_NAME,
PARSE_CASE_NAMES,
PARSE_START_DIR,
PARSE_REGRESSION_TEST_PATH,
PARSING_NONE
};
ArgumentParsingType argumentParsingType = PARSING_NONE;
bool showHelp = false;
bool isSaveSnapshotsForAllViews = false;
bool isRunRegressionTest = false;
bool isUpdateRegressionTest = false;
int i;
for (i = 1; i < arguments.size(); i++)
{
QString arg = arguments[i];
bool foundKnownOption = false;
if (arg.toLower() == "-help" || arg.toLower() == "-?")
{
showHelp = true;
foundKnownOption = true;
}
if (arg.toLower() == "-last")
{
openLatestProject = true;
foundKnownOption = true;
}
else if (arg.toLower() == "-project")
{
argumentParsingType = PARSE_PROJECT_FILE_NAME;
foundKnownOption = true;
}
else if (arg.toLower() == "-case")
{
argumentParsingType = PARSE_CASE_NAMES;
foundKnownOption = true;
}
else if (arg.toLower() == "-startdir")
{
argumentParsingType = PARSE_START_DIR;
foundKnownOption = true;
}
else if (arg.toLower() == "-savesnapshots")
{
isSaveSnapshotsForAllViews = true;
foundKnownOption = true;
}
else if (arg.toLower() == "-regressiontest")
{
isRunRegressionTest = true;
argumentParsingType = PARSE_REGRESSION_TEST_PATH;
foundKnownOption = true;
}
else if (arg.toLower() == "-updateregressiontestbase")
{
isUpdateRegressionTest = true;
argumentParsingType = PARSE_REGRESSION_TEST_PATH;
foundKnownOption = true;
}
if (!foundKnownOption)
{
switch (argumentParsingType)
{
case PARSE_PROJECT_FILE_NAME:
if (QFile::exists(arg))
{
projectFilename = arg;
}
break;
case PARSE_CASE_NAMES:
{
caseNames.append(arg);
}
break;
case PARSE_START_DIR:
{
m_startupDefaultDirectory = arg;
}
break;
case PARSE_REGRESSION_TEST_PATH:
{
regressionTestPath = arg;
}
}
}
}
if (showHelp)
{
QString helpText = commandLineParameterHelp();
#if defined(_MSC_VER) && defined(_WIN32)
showFormattedTextInMessageBox(helpText);
showFormattedTextInMessageBox(m_helpText);
#else
fprintf(stdout, "%s\n", helpText.toAscii().data());
fprintf(stdout, "%s\n", m_helpText.toAscii().data());
fflush(stdout);
#endif
return false;
}
if (isRunRegressionTest)
// Handling of the actual command line options
// --------------------------------------------------------
if (cvf::Option o = progOpt.option("regressiontest"))
{
CVF_ASSERT(o.valueCount() == 1);
QString regressionTestPath = cvfqt::Utils::toQString(o.value(0));
executeRegressionTests(regressionTestPath);
return false;
}
if (isUpdateRegressionTest)
if (cvf::Option o = progOpt.option("updateregressiontestbase"))
{
CVF_ASSERT(o.valueCount() == 1);
QString regressionTestPath = cvfqt::Utils::toQString(o.value(0));
updateRegressionTest(regressionTestPath);
return false;
}
if (openLatestProject)
if (cvf::Option o = progOpt.option("startdir"))
{
loadLastUsedProject();
CVF_ASSERT(o.valueCount() == 1);
m_startupDefaultDirectory = cvfqt::Utils::toQString(o.value(0));
}
if (!projectFilename.isEmpty())
{
loadProject(projectFilename);
}
if (!caseNames.isEmpty())
{
QString caseName;
foreach (caseName, caseNames)
{
QString tmpCaseFileName = caseName + ".EGRID";
if (QFile::exists(tmpCaseFileName))
if (cvf::Option o = progOpt.option("size"))
{
RiuMainWindow* mainWnd = RiuMainWindow::instance();
int width = o.safeValue(0).toInt(-1);
int height = o.safeValue(1).toInt(-1);
if (mainWnd && width > 0 && height > 0)
{
mainWnd->resize(width, height);
}
}
QString projectFileName;
if (progOpt.hasOption("last"))
{
projectFileName = m_preferences->lastUsedProjectFileName;
}
if (cvf::Option o = progOpt.option("project"))
{
CVF_ASSERT(o.valueCount() == 1);
projectFileName = cvfqt::Utils::toQString(o.value(0));
}
if (!projectFileName.isEmpty())
{
if (cvf::Option o = progOpt.option("multiCaseSnapshots"))
{
QString gridListFile = cvfqt::Utils::toQString(o.safeValue(0));
std::vector<QString> gridFiles = readFileListFromTextFile(gridListFile);
runMultiCaseSnapshots(projectFileName, gridFiles, "multiCaseSnapshots");
return false;
}
}
if (!projectFileName.isEmpty())
{
cvf::ref<RiaProjectModifier> projectModifier;
ProjectLoadAction projectLoadAction = PLA_NONE;
if (cvf::Option o = progOpt.option("replaceCase"))
{
if (projectModifier.isNull()) projectModifier = new RiaProjectModifier;
const int caseId = o.safeValue(0).toInt(-1);
if (caseId != -1 && o.valueCount() > 1)
{
openEclipseCaseFromFile(tmpCaseFileName);
QString gridFileName = cvfqt::Utils::toQString(o.value(1));
projectModifier->setReplaceCase(caseId, gridFileName);
}
else
{
tmpCaseFileName = caseName + ".GRID";
if (QFile::exists(tmpCaseFileName))
QString gridFileName = cvfqt::Utils::toQString(o.safeValue(0));
projectModifier->setReplaceCaseFirstOccurence(gridFileName);
}
}
if (cvf::Option o = progOpt.option("replaceSourceCases"))
{
if (projectModifier.isNull()) projectModifier = new RiaProjectModifier;
const int caseGroupId = o.safeValue(0).toInt(-1);
if (caseGroupId != -1 && o.valueCount() > 1)
{
std::vector<QString> gridFileNames = readFileListFromTextFile(cvfqt::Utils::toQString(o.value(1)));
projectModifier->setReplaceSourceCasesById(caseGroupId, gridFileNames);
}
else
{
std::vector<QString> gridFileNames = readFileListFromTextFile(cvfqt::Utils::toQString(o.safeValue(0)));
projectModifier->setReplaceSourceCasesFirstOccurence(gridFileNames);
}
projectLoadAction = PLA_CALCULATE_STATISTICS;
}
loadProject(projectFileName, projectLoadAction, projectModifier.p());
}
if (cvf::Option o = progOpt.option("case"))
{
QStringList caseNames = cvfqt::Utils::toQStringList(o.values());
foreach (QString caseName, caseNames)
{
QString caseFileNameWithExt = caseName + ".EGRID";
if (QFile::exists(caseFileNameWithExt))
{
openEclipseCaseFromFile(caseFileNameWithExt);
}
else
{
caseFileNameWithExt = caseName + ".GRID";
if (QFile::exists(caseFileNameWithExt))
{
openEclipseCaseFromFile(tmpCaseFileName);
openEclipseCaseFromFile(caseFileNameWithExt);
}
}
}
}
if (m_project.notNull() && !m_project->fileName().isEmpty() && isSaveSnapshotsForAllViews)
if (progOpt.hasOption("savesnapshots"))
{
saveSnapshotForAllViews("snapshots");
RiuMainWindow* mainWnd = RiuMainWindow::instance();
if (m_project.notNull() && !m_project->fileName().isEmpty() && mainWnd)
{
mainWnd->hideAllDockWindows();
// Will be saved relative to current directory
saveSnapshotForAllViews("snapshots");
mainWnd->loadWinGeoAndDockToolBarLayout();
}
// Returning false will exit the application
return false;
@@ -926,6 +997,37 @@ bool RiaApplication::parseArguments()
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<QString> RiaApplication::readFileListFromTextFile(QString listFileName)
{
std::vector<QString> fileList;
QFile file(listFileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
return fileList;
}
QTextStream in(&file);
QString line = in.readLine();
while (!line.isNull())
{
line = line.trimmed();
if (!line.isEmpty())
{
fileList.push_back(line);
}
line = in.readLine();
}
return fileList;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -1018,15 +1120,29 @@ bool RiaApplication::launchProcess(const QString& program, const QStringList& ar
m_workerProcess = new caf::UiProcess(this);
// Set the LD_LIBRARY_PATH to make the octave plugins find the embedded Qt
QProcessEnvironment penv = QProcessEnvironment::systemEnvironment();
QString ldPath = penv.value("LD_LIBRARY_PATH", "");
if (ldPath == "") ldPath = QApplication::applicationDirPath();
else ldPath = QApplication::applicationDirPath() + ":" + ldPath;
#ifdef WIN32
// Octave plugins compiled by ResInsight are dependent on Qt (currently Qt 32-bit only)
// Some Octave installations for Windows have included Qt, and some don't. To make sure these plugins always can be executed,
// the path to octave_plugin_dependencies is added to global path
QString pathString = penv.value("PATH", "");
if (pathString == "") pathString = QApplication::applicationDirPath() + "\\octave_plugin_dependencies";
else pathString = QApplication::applicationDirPath() + "\\octave_plugin_dependencies" + ";" + pathString;
penv.insert("PATH", pathString);
#else
// Set the LD_LIBRARY_PATH to make the octave plugins find the embedded Qt
QString ldPath = penv.value("LD_LIBRARY_PATH", "");
if (ldPath == "") ldPath = QApplication::applicationDirPath();
else ldPath = QApplication::applicationDirPath() + ":" + ldPath;
penv.insert("LD_LIBRARY_PATH", ldPath);
#endif
penv.insert("LD_LIBRARY_PATH", ldPath);
m_workerProcess->setProcessEnvironment(penv);
connect(m_workerProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(slotWorkerProcessFinished(int, QProcess::ExitStatus)));
@@ -1195,6 +1311,7 @@ void RiaApplication::setDefaultFileDialogDirectory(const QString& dialogName, co
m_fileDialogDefaultDirectories[dialogName] = defaultDirectory;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -1270,18 +1387,14 @@ void RiaApplication::saveSnapshotForAllViews(const QString& snapshotFolderName)
if (m_project.isNull()) return;
if (m_project->fileName().isEmpty()) return;
QFileInfo fi(m_project->fileName());
QDir projectDir(fi.absolutePath());
if (!projectDir.exists(snapshotFolderName))
QDir snapshotPath(snapshotFolderName);
if (!snapshotPath.exists())
{
if (!projectDir.mkdir(snapshotFolderName)) return;
if (!snapshotPath.mkpath(".")) return;
}
QString snapshotPath = projectDir.absolutePath();
snapshotPath += "/" + snapshotFolderName;
const QString absSnapshotPath = snapshotPath.absolutePath();
std::vector<RimCase*> projectCases;
m_project->allCases(projectCases);
@@ -1306,14 +1419,45 @@ void RiaApplication::saveSnapshotForAllViews(const QString& snapshotFolderName)
QCoreApplication::processEvents();
QString fileName = ri->caseUserDescription() + "-" + riv->name();
fileName.replace(" ", "_");
QString absoluteFileName = caf::Utils::constructFullFileName(snapshotPath, fileName, ".png");
QString absoluteFileName = caf::Utils::constructFullFileName(absSnapshotPath, fileName, ".png");
saveSnapshotAs(absoluteFileName);
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaApplication::runMultiCaseSnapshots(const QString& templateProjectFileName, std::vector<QString> gridFileNames, const QString& snapshotFolderName)
{
RiuMainWindow* mainWnd = RiuMainWindow::instance();
if (!mainWnd) return;
mainWnd->hideAllDockWindows();
const size_t numGridFiles = gridFileNames.size();
for (size_t i = 0; i < numGridFiles; i++)
{
QString gridFn = gridFileNames[i];
RiaProjectModifier modifier;
modifier.setReplaceCaseFirstOccurence(gridFn);
bool loadOk = loadProject(templateProjectFileName, PLA_NONE, &modifier);
if (loadOk)
{
saveSnapshotForAllViews(snapshotFolderName);
}
}
mainWnd->loadWinGeoAndDockToolBarLayout();
}
void removeDirectoryWithContent(QDir dirToDelete )
{
QStringList files = dirToDelete.entryList();
@@ -1384,8 +1528,20 @@ void RiaApplication::runRegressionTest(const QString& testRootPath)
// Open HTML report
QDesktopServices::openUrl(htmlReportFileName);
// Generate diff images
this->preferences()->resetToDefaults();
// Keep current preferences values to be able to restore when regression tests are completed
std::vector<QVariant> preferencesValues;
{
std::vector<caf::PdmFieldHandle*> fields;
this->preferences()->fields(fields);
for (size_t i = 0; i < fields.size(); i++)
{
QVariant v = fields[i]->uiValue();
preferencesValues.push_back(v);
}
}
// Set preferences to make sure regression tests behave identical
this->preferences()->configureForRegressionTests();
for (int dirIdx = 0; dirIdx < folderList.size(); ++dirIdx)
{
@@ -1401,9 +1557,10 @@ void RiaApplication::runRegressionTest(const QString& testRootPath)
}
m_commandQueueLock.unlock();
regressionTestSetFixedSizeForAllViews();
regressionTestConfigureProject();
saveSnapshotForAllViews(generatedFolderName);
QString fullPathGeneratedFolder = testCaseFolder.absoluteFilePath(generatedFolderName);
saveSnapshotForAllViews(fullPathGeneratedFolder);
QDir baseDir(testCaseFolder.filePath(baseFolderName));
QDir genDir(testCaseFolder.filePath(generatedFolderName));
@@ -1425,6 +1582,18 @@ void RiaApplication::runRegressionTest(const QString& testRootPath)
closeProject(false);
}
// Restore preferences
{
std::vector<caf::PdmFieldHandle*> fields;
this->preferences()->fields(fields);
CVF_ASSERT(fields.size() == preferencesValues.size());
for (size_t i = 0; i < preferencesValues.size(); i++)
{
fields[i]->setValueFromUi(preferencesValues[i]);
}
}
}
}
@@ -1622,6 +1791,9 @@ void RiaApplication::showFormattedTextInMessageBox(const QString& text)
//--------------------------------------------------------------------------------------------------
QString RiaApplication::commandLineParameterHelp() const
{
return m_helpText;
/*
QString text = QString("\n%1 v. %2\n").arg(RI_APPLICATION_NAME).arg(getVersionStringApp(false));
text += "Copyright Statoil ASA, Ceetron AS 2011, 2012\n\n";
@@ -1654,6 +1826,7 @@ QString RiaApplication::commandLineParameterHelp() const
"-----------------------------------------------------------------";
return text;
*/
}
//--------------------------------------------------------------------------------------------------
@@ -1788,7 +1961,7 @@ void RiaApplication::executeRegressionTests(const QString& regressionTestPath)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaApplication::regressionTestSetFixedSizeForAllViews()
void RiaApplication::regressionTestConfigureProject()
{
RiuMainWindow* mainWnd = RiuMainWindow::instance();
if (!mainWnd) return;
@@ -1812,6 +1985,9 @@ void RiaApplication::regressionTestSetFixedSizeForAllViews()
// This size is set to match the regression test reference images
riv->viewer()->setFixedSize(1000, 745);
}
riv->faultCollection->showFaultsOutsideFilters.setValueFromUi(false);
riv->faultCollection->showResultsOnFaults.setValueFromUi(true);
}
}
}

View File

@@ -38,6 +38,7 @@ class RiaPreferences;
class RimReservoirView;
class RimProject;
class RimCommandObject;
class RiaProjectModifier;
namespace caf
{
@@ -90,9 +91,9 @@ public:
bool addEclipseCases(const QStringList& fileNames);
bool openInputEclipseCaseFromFileNames(const QStringList& fileNames);
bool loadLastUsedProject();
QString currentProjectFileName() const;
bool loadProject(const QString& fileName);
QString createAbsolutePathFromProjectRelativePath(QString projectRelativePath);
bool loadProject(const QString& projectFileName);
bool saveProject();
bool saveProjectAs(const QString& fileName);
bool saveProjectPromptForFileName();
@@ -103,13 +104,14 @@ public:
void saveSnapshotPromtpForFilename();
void saveSnapshotAs(const QString& fileName);
void saveSnapshotForAllViews(const QString& snapshotFolderName);
void runMultiCaseSnapshots(const QString& templateProjectFileName, std::vector<QString> gridFileNames, const QString& snapshotFolderName);
void runRegressionTest(const QString& testRootPath);
void updateRegressionTest(const QString& testRootPath );
void regressionTestSetFixedSizeForAllViews();
void regressionTestConfigureProject();
void processNonGuiEvents();
static const char* getVersionStringApp(bool includeCrtInfo);
static const char* getVersionStringApp(bool includeCrtInfo);
void setUseShaders(bool enable);
bool useShaders() const;
@@ -143,10 +145,18 @@ public:
void executeCommandObjects();
private:
void onProjectOpenedOrClosed();
void setWindowCaptionFromAppState();
enum ProjectLoadAction
{
PLA_NONE = 0,
PLA_CALCULATE_STATISTICS = 1
};
bool loadProject(const QString& projectFileName, ProjectLoadAction loadAction, RiaProjectModifier* projectModifier);
void onProjectOpenedOrClosed();
std::vector<QString> readFileListFromTextFile(QString listFileName);
void setWindowCaptionFromAppState();
QImage grabFrameBufferImage();
QImage grabFrameBufferImage();
private slots:
void slotWorkerProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
@@ -180,4 +190,6 @@ private:
std::list<RimCommandObject*> m_commandQueue;
QMutex m_commandQueueLock;
QString m_helpText;
};

View File

@@ -48,7 +48,6 @@ RiaPreferences::RiaPreferences(void)
CAF_PDM_InitField(&defaultViewerBackgroundColor, "defaultViewerBackgroundColor", cvf::Color3f(0.69f, 0.77f, 0.87f), "Viewer background", "", "The viewer background color for new views", "");
CAF_PDM_InitField(&defaultScaleFactorZ, "defaultScaleFactorZ", 5, "Z scale factor", "", "", "");
CAF_PDM_InitField(&useShaders, "useShaders", true, "Use Shaders", "", "", "");
@@ -59,6 +58,8 @@ RiaPreferences::RiaPreferences(void)
CAF_PDM_InitField(&autocomputeSOIL, "autocomputeSOIL", true, "SOIL", "", "SOIL = 1.0 - SGAS - SWAT", "");
CAF_PDM_InitField(&autocomputeDepthRelatedProperties,"autocomputeDepth", true, "DEPTH related properties", "", "DEPTH, DX, DY, DZ, TOP, BOTTOM", "");
CAF_PDM_InitField(&readFaultData, "readFaultData", true, "Read fault data", "", "", "");
}
//--------------------------------------------------------------------------------------------------
@@ -108,17 +109,23 @@ void RiaPreferences::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering&
caf::PdmUiGroup* autoComputeGroup = uiOrdering.addNewGroup("Compute when loading new case");
autoComputeGroup->add(&autocomputeSOIL);
autoComputeGroup->add(&autocomputeDepthRelatedProperties);
caf::PdmUiGroup* faultsGroup = uiOrdering.addNewGroup("Faults");
faultsGroup->add(&readFaultData);
}
//--------------------------------------------------------------------------------------------------
///
/// This function is called as part of the regression test system to make sure the configuration
/// for regression tests is consistent
//--------------------------------------------------------------------------------------------------
void RiaPreferences::resetToDefaults()
void RiaPreferences::configureForRegressionTests()
{
useShaders = true;
showHud = false;
autocomputeSOIL = true;
autocomputeDepthRelatedProperties = true;
readFaultData = false;
}

View File

@@ -33,7 +33,7 @@ public:
RiaPreferences(void);
virtual ~RiaPreferences(void);
void resetToDefaults();
void configureForRegressionTests();
public: // Pdm Fields
caf::PdmField<caf::AppEnum< RiaApplication::RINavigationPolicy > > navigationPolicy;
@@ -58,6 +58,7 @@ public: // Pdm Fields
caf::PdmField<bool> autocomputeSOIL;
caf::PdmField<bool> autocomputeDepthRelatedProperties;
caf::PdmField<bool> readFaultData;
protected:
virtual void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute);

View File

@@ -0,0 +1,255 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RiaStdInclude.h"
#include "RiaProjectModifier.h"
#include "RimProject.h"
#include "RimAnalysisModels.h"
#include "RimOilField.h"
#include "RimIdenticalGridCaseGroup.h"
#include "RimCaseCollection.h"
#include "RimResultCase.h"
#include "RimReservoirView.h"
#include "RimWellPathCollection.h"
#include "RimScriptCollection.h"
#include "RimCellPropertyFilterCollection.h"
#include "RimCellPropertyFilter.h"
#include "RimReservoirCellResultsCacher.h"
#include "RimResultSlot.h"
#include "RimCellEdgeResultSlot.h"
#include "RimCellRangeFilterCollection.h"
#include "RimWellCollection.h"
#include "Rim3dOverlayInfoConfig.h"
//==================================================================================================
//
//
//
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaProjectModifier::RiaProjectModifier()
: m_replaceCase_caseId(UNDEFINED),
m_replaceSourceCases_caseGroupId(UNDEFINED)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaProjectModifier::setReplaceCaseFirstOccurence(QString newGridFileName)
{
m_replaceCase_caseId = FIRST_OCCURENCE;
m_replaceCase_gridFileName = makeFilePathAbsolute(newGridFileName);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaProjectModifier::setReplaceCase(int caseIdToReplace, QString newGridFileName)
{
if (caseIdToReplace >= 0)
{
m_replaceCase_caseId = caseIdToReplace;
m_replaceCase_gridFileName = makeFilePathAbsolute(newGridFileName);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaProjectModifier::setReplaceSourceCasesFirstOccurence(std::vector<QString> newGridFileNames)
{
m_replaceSourceCases_caseGroupId = FIRST_OCCURENCE;
m_replaceSourceCases_gridFileNames.clear();
foreach (QString fn, newGridFileNames)
{
m_replaceSourceCases_gridFileNames.push_back(makeFilePathAbsolute(fn));
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaProjectModifier::setReplaceSourceCasesById(int caseGroupIdToReplace, std::vector<QString> newGridFileNames)
{
if (caseGroupIdToReplace >= 0)
{
m_replaceSourceCases_caseGroupId = caseGroupIdToReplace;
m_replaceSourceCases_gridFileNames.clear();
foreach (QString fn, newGridFileNames)
{
m_replaceSourceCases_gridFileNames.push_back(makeFilePathAbsolute(fn));
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RiaProjectModifier::applyModificationsToProject(RimProject* project)
{
if (m_replaceCase_caseId != UNDEFINED && !m_replaceCase_gridFileName.isEmpty())
{
replaceCase(project);
}
if (m_replaceSourceCases_caseGroupId != UNDEFINED && m_replaceSourceCases_gridFileNames.size() > 0)
{
replaceSourceCases(project);
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RiaProjectModifier::replaceSourceCases(RimProject* project)
{
bool didReplacement = false;
for (size_t oilFieldIdx = 0; oilFieldIdx < project->oilFields().size(); oilFieldIdx++)
{
RimOilField* oilField = project->oilFields[oilFieldIdx];
RimAnalysisModels* analysisModels = oilField ? oilField->analysisModels() : NULL;
if (analysisModels)
{
const size_t numCaseGroups = analysisModels->caseGroups.size();
for (size_t caseGrpIdx = 0; caseGrpIdx < numCaseGroups; ++caseGrpIdx)
{
RimIdenticalGridCaseGroup* caseGroup = analysisModels->caseGroups[caseGrpIdx];
if (m_replaceSourceCases_caseGroupId == FIRST_OCCURENCE ||
m_replaceSourceCases_caseGroupId == caseGroup->groupId)
{
RimCaseCollection* caseCollection = caseGroup->caseCollection;
caseCollection->reservoirs.deleteAllChildObjects();
for (size_t i = 0; i < m_replaceSourceCases_gridFileNames.size(); i++)
{
QString fileName = m_replaceSourceCases_gridFileNames[i];
QString caseName = caseNameFromGridFileName(fileName);
// Use this slightly hackish method in order to get a new unique ID
RimResultCase* resCase = new RimResultCase;
resCase->setCaseInfo(caseName, fileName);
caseCollection->reservoirs.push_back(resCase);
}
didReplacement = true;
if (m_replaceSourceCases_caseGroupId == FIRST_OCCURENCE)
{
return true;
}
}
}
}
}
return didReplacement;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RiaProjectModifier::replaceCase(RimProject* project)
{
bool didReplacement = false;
for (size_t oilFieldIdx = 0; oilFieldIdx < project->oilFields().size(); oilFieldIdx++)
{
RimOilField* oilField = project->oilFields[oilFieldIdx];
RimAnalysisModels* analysisModels = oilField ? oilField->analysisModels() : NULL;
if (analysisModels)
{
for (size_t caseIdx = 0; caseIdx < analysisModels->cases.size(); ++caseIdx)
{
RimResultCase* resultCase = dynamic_cast<RimResultCase*>(analysisModels->cases[caseIdx]);
if (resultCase)
{
if (m_replaceCase_caseId == FIRST_OCCURENCE ||
m_replaceCase_caseId == resultCase->caseId())
{
resultCase->setGridFileName(m_replaceCase_gridFileName);
resultCase->caseUserDescription = caseNameFromGridFileName(m_replaceCase_gridFileName);
didReplacement = true;
if (m_replaceCase_caseId == FIRST_OCCURENCE)
{
return true;
}
}
}
}
}
}
return didReplacement;
}
//--------------------------------------------------------------------------------------------------
/// Returns absolute path name to the specified file.
///
/// If \a relOrAbsolutePath is a relative, the current working directory for the process will be
/// used in order to make the path absolute.
//--------------------------------------------------------------------------------------------------
QString RiaProjectModifier::makeFilePathAbsolute(QString relOrAbsolutePath)
{
QFileInfo theFile(relOrAbsolutePath);
theFile.makeAbsolute();
return theFile.filePath();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RiaProjectModifier::caseNameFromGridFileName(QString fullGridFilePathName)
{
QString fn = QDir::fromNativeSeparators(fullGridFilePathName);
// Extract file name plus the 'deepest' directory
QString deepestDirPlusFileName = fn.section('/', -2, -1);
deepestDirPlusFileName.replace("/", "--");
return deepestDirPlusFileName;
}

View File

@@ -0,0 +1,62 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
class RimProject;
//==================================================================================================
//
//
//
//==================================================================================================
class RiaProjectModifier : public cvf::Object
{
public:
RiaProjectModifier();
void setReplaceCaseFirstOccurence(QString newGridFileName);
void setReplaceCase(int caseIdToReplace, QString newGridFileName);
void setReplaceSourceCasesFirstOccurence(std::vector<QString> newGridFileNames);
void setReplaceSourceCasesById(int caseGroupIdToReplace, std::vector<QString> newGridFileNames);
bool applyModificationsToProject(RimProject* project);
private:
bool replaceSourceCases(RimProject* project);
bool replaceCase(RimProject* project);
static QString makeFilePathAbsolute(QString relOrAbsolutePath);
static QString caseNameFromGridFileName(QString fullGridFilePathName);
private:
int m_replaceCase_caseId;
QString m_replaceCase_gridFileName;
int m_replaceSourceCases_caseGroupId;
std::vector<QString> m_replaceSourceCases_gridFileNames;
static const int UNDEFINED = -1;
static const int FIRST_OCCURENCE = -999;
};

View File

@@ -21,7 +21,7 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/ReservoirDataModel
${CMAKE_CURRENT_SOURCE_DIR}/WellPathImportSsihub
${CMAKE_BINARY_DIR}/Generated
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
@@ -34,9 +34,10 @@ set( APPLICATION_FILES
Application/RiaApplication.cpp
Application/RiaPreferences.cpp
Application/RiaImageFileCompare.cpp
Application/RiaImageCompareReporter.cpp
Application/RiaRegressionTest.cpp
Application/RiaImageFileCompare.cpp
Application/RiaImageCompareReporter.cpp
Application/RiaProjectModifier.cpp
Application/RiaRegressionTest.cpp
)
set( USER_INTERFACE_FILES
@@ -46,7 +47,7 @@ set( USER_INTERFACE_FILES
UserInterface/RiuResultInfoPanel.cpp
UserInterface/RiuViewer.cpp
UserInterface/RiuSimpleHistogramWidget.cpp
UserInterface/RiuMultiCaseImportDialog.cpp
UserInterface/RiuMultiCaseImportDialog.cpp
UserInterface/RiuProcessMonitor.cpp
)
@@ -56,7 +57,7 @@ set( SOCKET_INTERFACE_FILES
SocketInterface/RiaCaseInfoCommands.cpp
SocketInterface/RiaGeometryCommands.cpp
SocketInterface/RiaPropertyDataCommands.cpp
SocketInterface/RiaWellDataCommands.cpp
SocketInterface/RiaWellDataCommands.cpp
SocketInterface/RiaSocketTools.cpp
)
@@ -101,15 +102,15 @@ set ( QT_MOC_HEADERS
UserInterface/RiuResultInfoPanel.h
UserInterface/RiuViewer.h
UserInterface/RiuProcessMonitor.h
SocketInterface/RiaSocketServer.h
UserInterface/RiuMultiCaseImportDialog.h
SocketInterface/RiaSocketServer.h
UserInterface/RiuMultiCaseImportDialog.h
)
qt4_wrap_cpp( MOC_FILES_CPP ${QT_MOC_HEADERS} )
# Define files for the uic compiler
set ( QT_UI_FILES
UserInterface/RiuMultiCaseImportDialog.ui
UserInterface/RiuMultiCaseImportDialog.ui
)
qt4_wrap_ui( FORM_FILES_CPP ${QT_UI_FILES} )
@@ -141,19 +142,19 @@ endif()
set( RAW_SOURCES ${CPP_SOURCES} )
list( REMOVE_ITEM RAW_SOURCES
RiaStdInclude.cpp
RiaStdInclude.cpp
${CODE_SOURCE_FILES}
${CODE_SOURCE_FILES}
ModelVisualization/RivCellEdgeEffectGenerator.cpp
ModelVisualization/RivPipeGeometryGenerator.cpp
ModelVisualization/RivWellPipesPartMgr.cpp
ModelVisualization/RivWellHeadPartMgr.cpp
Application/RiaImageFileCompare.cpp
Application/RiaImageCompareReporter.cpp
Application/RiaRegressionTest.cpp
ModelVisualization/RivCellEdgeEffectGenerator.cpp
ModelVisualization/RivPipeGeometryGenerator.cpp
ModelVisualization/RivWellPipesPartMgr.cpp
ModelVisualization/RivWellHeadPartMgr.cpp
Application/RiaImageFileCompare.cpp
Application/RiaImageCompareReporter.cpp
Application/RiaRegressionTest.cpp
FileInterface/RifEclipseInputFileTools.cpp
FileInterface/RifEclipseOutputFileTools.cpp
FileInterface/RifEclipseRestartFilesetAccess.cpp
@@ -210,11 +211,11 @@ set( EXE_FILES
${EXE_FILES}
${CPP_SOURCES}
${MOC_FILES_CPP}
${FORM_FILES_CPP}
${FORM_FILES_CPP}
${QRC_FILES_CPP}
${WIN_RESOURCE}
${HEADER_FILES}
${REFERENCED_CMAKE_FILES}
${HEADER_FILES}
${REFERENCED_CMAKE_FILES}
../ResInsightVersion.cmake
)
@@ -249,8 +250,8 @@ set( EXTERNAL_LINK_LIBRARIES ${ERT_LIBRARY_LIST} )
# According to ivarun this is needed on OpenSuse, and Fedora. See: https://github.com/OPM/ResInsight/pull/7
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set ( EXTERNAL_LINK_LIBRARIES
${EXTERNAL_LINK_LIBRARIES}
rt
${EXTERNAL_LINK_LIBRARIES}
rt
)
endif()
@@ -282,70 +283,70 @@ set (RESINSIGHT_LICENSE_FILES
# bundle libraries together with private installation
if (RESINSIGHT_PRIVATE_INSTALL)
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
# tell binary to first attempt to load libraries from its own directory
set_target_properties (ResInsight PROPERTIES INSTALL_RPATH "\$ORIGIN")
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
# tell binary to first attempt to load libraries from its own directory
set_target_properties (ResInsight PROPERTIES INSTALL_RPATH "\$ORIGIN")
# Find Qt libraries and sym links
file (GLOB RESINSIGHT_FILES
${QT_LIBRARY_DIR}/libQtCore.so*
${QT_LIBRARY_DIR}/libQtGui.so*
${QT_LIBRARY_DIR}/libQtOpenGL.so*
${QT_LIBRARY_DIR}/libQtNetwork.so*
${QT_LIBRARY_DIR}/libQtScript.so*
${QT_LIBRARY_DIR}/libQtScriptTools.so*
)
# Find Qt libraries and sym links
file (GLOB RESINSIGHT_FILES
${QT_LIBRARY_DIR}/libQtCore.so*
${QT_LIBRARY_DIR}/libQtGui.so*
${QT_LIBRARY_DIR}/libQtOpenGL.so*
${QT_LIBRARY_DIR}/libQtNetwork.so*
${QT_LIBRARY_DIR}/libQtScript.so*
${QT_LIBRARY_DIR}/libQtScriptTools.so*
)
endif()
endif()
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
# put a .exe.local file in the target directory to pick up DLLs from there
install (CODE "exec_program (${CMAKE_COMMAND} ARGS -E touch \$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}${RESINSIGHT_FINAL_NAME}/ResInsight${CMAKE_EXECUTABLE_SUFFIX}.local)")
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
# put a .exe.local file in the target directory to pick up DLLs from there
install (CODE "exec_program (${CMAKE_COMMAND} ARGS -E touch \$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}${RESINSIGHT_FINAL_NAME}/ResInsight${CMAKE_EXECUTABLE_SUFFIX}.local)")
set (RESINSIGHT_FILES
${QT_BINARY_DIR}/QtCore4.dll
${QT_BINARY_DIR}/QtGui4.dll
${QT_BINARY_DIR}/QtOpenGL4.dll
${QT_BINARY_DIR}/QtNetwork4.dll
${QT_BINARY_DIR}/QtScript4.dll
${QT_BINARY_DIR}/QtScriptTools4.dll
)
endif()
set (RESINSIGHT_FILES
${QT_BINARY_DIR}/QtCore4.dll
${QT_BINARY_DIR}/QtGui4.dll
${QT_BINARY_DIR}/QtOpenGL4.dll
${QT_BINARY_DIR}/QtNetwork4.dll
${QT_BINARY_DIR}/QtScript4.dll
${QT_BINARY_DIR}/QtScriptTools4.dll
)
endif()
set (RESINSIGHT_FILES ${RESINSIGHT_FILES} ${RESINSIGHT_LICENSE_FILES})
set (RESINSIGHT_FILES ${RESINSIGHT_FILES} ${RESINSIGHT_LICENSE_FILES})
install(TARGETS ResInsight DESTINATION ${RESINSIGHT_FINAL_NAME})
install(TARGETS ResInsight DESTINATION ${RESINSIGHT_FINAL_NAME})
install(FILES ${RESINSIGHT_FILES} DESTINATION ${RESINSIGHT_FINAL_NAME} )
install(FILES ${RESINSIGHT_FILES} DESTINATION ${RESINSIGHT_FINAL_NAME} )
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resinsight DESTINATION ${RESINSIGHT_FINAL_NAME} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE )
endif()
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resinsight DESTINATION ${RESINSIGHT_FINAL_NAME} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE )
endif()
else (RESINSIGHT_PRIVATE_INSTALL)
# binaries go in /usr/bin
install (TARGETS ResInsight
DESTINATION bin
)
DESTINATION bin
)
# license go in /usr/share/doc
install (FILES ${RESINSIGHT_LICENSE_FILES}
DESTINATION share/doc/ResInsight
)
DESTINATION share/doc/ResInsight
)
# no bundled libraries for system install
# application icon
install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/Resources/AppLogo48x48.png
DESTINATION share/icons/hicolor/48x48/apps
RENAME ResInsight.png
)
DESTINATION share/icons/hicolor/48x48/apps
RENAME ResInsight.png
)
# desktop environment icon; remember to call `update-desktop-database`
# in package post-install scripts
configure_file (
${CMAKE_CURRENT_SOURCE_DIR}/resinsight.desktop.in
${CMAKE_CURRENT_BINARY_DIR}/resinsight.desktop
@ONLY
)
${CMAKE_CURRENT_SOURCE_DIR}/resinsight.desktop.in
${CMAKE_CURRENT_BINARY_DIR}/resinsight.desktop
@ONLY
)
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/resinsight.desktop
DESTINATION share/applications
)
DESTINATION share/applications
)
endif (RESINSIGHT_PRIVATE_INSTALL)

View File

@@ -38,6 +38,9 @@
#include "RigCaseData.h"
#include "RifReaderEclipseInput.h"
#include "RifEclipseInputFileTools.h"
#include <QFile>
#if 0
//--------------------------------------------------------------------------------------------------
@@ -100,6 +103,8 @@ TEST(RigReservoirTest, WellTestErt)
well_info_free( well_info );
}
//--------------------------------------------------------------------------------------------------
/// This file contains test code taken from the test cases in ERT source code.
// There is a typedef issue (center) between ERT and QTextStream, so this file does not include any
@@ -107,12 +112,88 @@ TEST(RigReservoirTest, WellTestErt)
//--------------------------------------------------------------------------------------------------
TEST(RigReservoirTest, ElipseInputGridFile)
{
RigReservoir res;
RigCaseData res;
RifReaderEclipseInput inputReader;
bool result = inputReader.open("TEST10K_FLT_LGR_NNC.grdecl", &res);
EXPECT_TRUE(result);
EXPECT_EQ(size_t(1), res.mainGrid()->cells().size());
EXPECT_EQ(size_t(1), res.mainGrid()->globalMatrixModelActiveCellCount());
}
TEST(RigReservoirTest, ReadFaults)
{
// QString filename("d:/Models/Statoil/testcase_juli_2011/data/grid_local.grdecl");
//
// std::vector< RifKeywordAndFilePos > fileKeywords;
// RifEclipseInputFileTools::findKeywordsOnFile(filename, fileKeywords);
//
// cvf::Collection<RigFault> faults;
//
// RifEclipseInputFileTools::readFaults(filename, faults, fileKeywords);
// for (size_t j = 0; j < faults.size(); j++)
// {
// printf(faults.at(j)->name().toLatin1());
// printf("\n");
// }
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST(RigReservoirTest, ReadFaultsRecursively)
{
//TODO: Establish a way to define location of test model files
QString filename("d:/Models/Statoil/TEST_RKMFAULTS/TEST_RKMFAULTS.DATA");
// QString filename("d:/gitroot/ResInsight/TestModels/fault_test/regular27cell.DATA");
QString outFilename = "c:/tmp/TestModels/TEST_RKMFAULTS/msj_faults.txt";
QFile outputFile(outFilename);
{
if (!outputFile.open(QIODevice::WriteOnly))
{
return;
}
}
QTextStream outStream(&outputFile);
cvf::Collection<RigFault> faults;
RifEclipseInputFileTools::readFaultsInGridSection(filename, faults);
// EXPECT_EQ(4, faults.size());
for (size_t j = 0; j < faults.size(); j++)
{
const RigFault* rigFault = faults.at(j);
printf(rigFault->name().toLatin1());
for (size_t faceType = 0; faceType < 6; faceType++)
{
cvf::StructGridInterface::FaceType faceEnum = cvf::StructGridInterface::FaceType(faceType);
const std::vector<cvf::CellRange>& cellRanges = rigFault->cellRangeForFace(faceEnum);
for (size_t i = 0; i < cellRanges.size(); i++)
{
cvf::Vec3st min, max;
cellRanges[i].range(min, max);
QString tmp;
tmp = tmp.sprintf("min i=%3d j=%3d k=%3d - max i=%3d j=%3d k=%3d \n", min.x(), min.y(), min.z(), max.x(), max.y(), max.z());
outStream << tmp;
// printf("min i=%3d j=%3d k=%3d - max i=%3d j=%3d k=%3d ", min.x(), min.y(), min.z(), max.x(), max.y(), max.z());
// printf("\n");
}
}
}
}
#endif

View File

@@ -28,6 +28,8 @@
#include <iostream>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QTextStream>
#include <QDebug>
@@ -35,10 +37,14 @@
#include "well_state.h"
#include "util.h"
#include <fstream>
#include "RigGridScalarDataAccess.h"
QString includeKeyword("INCLUDE");
QString faultsKeyword("FAULTS");
QString editKeyword("EDIT");
QString gridKeyword("GRID");
//--------------------------------------------------------------------------------------------------
/// Constructor
@@ -61,17 +67,20 @@ RifEclipseInputFileTools::~RifEclipseInputFileTools()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseInputFileTools::openGridFile(const QString& fileName, RigCaseData* eclipseCase)
bool RifEclipseInputFileTools::openGridFile(const QString& fileName, RigCaseData* eclipseCase, bool readFaultData)
{
CVF_ASSERT(eclipseCase);
std::vector< RifKeywordAndFilePos > keywordsAndFilePos;
findKeywordsOnFile(fileName, keywordsAndFilePos);
qint64 coordPos = -1;
qint64 zcornPos = -1;
qint64 specgridPos = -1;
qint64 actnumPos = -1;
qint64 mapaxesPos = -1;
findGridKeywordPositions(fileName, &coordPos, &zcornPos, &specgridPos, &actnumPos, &mapaxesPos);
findGridKeywordPositions(keywordsAndFilePos, &coordPos, &zcornPos, &specgridPos, &actnumPos, &mapaxesPos);
if (coordPos < 0 || zcornPos < 0 || specgridPos < 0)
{
@@ -99,7 +108,7 @@ bool RifEclipseInputFileTools::openGridFile(const QString& fileName, RigCaseData
ecl_kw_type* mapAxesKw = NULL;
// Try to read all the needed keywords. Early exit if some are not found
caf::ProgressInfo progress(7, "Read Grid from Eclipse Input file");
caf::ProgressInfo progress(8, "Read Grid from Eclipse Input file");
@@ -157,6 +166,18 @@ bool RifEclipseInputFileTools::openGridFile(const QString& fileName, RigCaseData
RifReaderEclipseOutput::transferGeometry(inputGrid, eclipseCase);
progress.setProgress(7);
progress.setProgressDescription("Read faults ...");
if (readFaultData)
{
cvf::Collection<RigFault> faults;
RifEclipseInputFileTools::readFaults(fileName, faults, keywordsAndFilePos);
RigMainGrid* mainGrid = eclipseCase->mainGrid();
mainGrid->setFaults(faults);
}
progress.setProgress(8);
progress.setProgressDescription("Cleaning up ...");
ecl_kw_free(specGridKw);
@@ -189,7 +210,8 @@ std::map<QString, QString> RifEclipseInputFileTools::readProperties(const QStri
caf::ProgressInfo mainProgress(2, "Reading Eclipse Input properties");
caf::ProgressInfo startProgress(knownKeywordSet.size(), "Scanning for known properties");
std::vector<RifKeywordAndFilePos> fileKeywords = RifEclipseInputFileTools::findKeywordsOnFile(fileName);
std::vector<RifKeywordAndFilePos> fileKeywords;
RifEclipseInputFileTools::findKeywordsOnFile(fileName, fileKeywords);
mainProgress.setProgress(1);
caf::ProgressInfo progress(fileKeywords.size(), "Reading properties");
@@ -242,10 +264,8 @@ std::map<QString, QString> RifEclipseInputFileTools::readProperties(const QStri
// https://bugreports.qt-project.org/browse/QTBUG-9814
//
//--------------------------------------------------------------------------------------------------
std::vector< RifKeywordAndFilePos > RifEclipseInputFileTools::findKeywordsOnFile(const QString &fileName)
void RifEclipseInputFileTools::findKeywordsOnFile(const QString &fileName, std::vector< RifKeywordAndFilePos >& keywords)
{
std::vector< RifKeywordAndFilePos > keywords;
char buf[1024];
QFile data(fileName);
@@ -274,8 +294,6 @@ std::vector< RifKeywordAndFilePos > RifEclipseInputFileTools::findKeywordsOnFile
}
}
while (lineLength != -1);
return keywords;
}
//--------------------------------------------------------------------------------------------------
@@ -484,12 +502,10 @@ void RifEclipseInputFileTools::writeDataToTextFile(QFile* file, const QString& e
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::findGridKeywordPositions(const QString& filename, qint64* coordPos, qint64* zcornPos, qint64* specgridPos, qint64* actnumPos, qint64* mapaxesPos)
void RifEclipseInputFileTools::findGridKeywordPositions(const std::vector< RifKeywordAndFilePos >& keywordsAndFilePos, qint64* coordPos, qint64* zcornPos, qint64* specgridPos, qint64* actnumPos, qint64* mapaxesPos)
{
CVF_ASSERT(coordPos && zcornPos && specgridPos && actnumPos && mapaxesPos);
std::vector< RifKeywordAndFilePos > keywordsAndFilePos = findKeywordsOnFile(filename);
size_t i;
for (i = 0; i < keywordsAndFilePos.size(); i++)
{
@@ -549,3 +565,312 @@ bool RifEclipseInputFileTools::readPropertyAtFilePosition(const QString& fileNam
util_fclose(filePointer);
return isOk;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::readFaults(const QString& fileName, cvf::Collection<RigFault>& faults, const std::vector<RifKeywordAndFilePos>& fileKeywords)
{
QFile data(fileName);
if (!data.open(QFile::ReadOnly))
{
return;
}
// Parse complete file if no keywords are parsed
if (fileKeywords.size() == 0)
{
qint64 filePos = findKeyword(faultsKeyword, data, 0);
while (filePos != -1)
{
readFaults(data, filePos, faults, NULL);
filePos = findKeyword(faultsKeyword, data, filePos);
}
return;
}
for (size_t i = 0; i < fileKeywords.size(); i++)
{
if (fileKeywords[i].keyword.compare(editKeyword, Qt::CaseInsensitive) == 0)
{
return;
}
else if (fileKeywords[i].keyword.compare(faultsKeyword, Qt::CaseInsensitive) != 0)
{
continue;
}
qint64 filePos = fileKeywords[i].filePos;
bool isEditKeywordDetected = false;
readFaults(data, filePos, faults, &isEditKeywordDetected);
if (isEditKeywordDetected)
{
return;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::readFaultsInGridSection(const QString& fileName, cvf::Collection<RigFault>& faults, std::vector<QString>& filenamesWithFaults)
{
QFile data(fileName);
if (!data.open(QFile::ReadOnly))
{
return;
}
QString gridKeyword("GRID");
// Search for keyword grid
qint64 gridPos = findKeyword(gridKeyword, data, 0);
if (gridPos < 0)
{
return;
}
bool isEditKeywordDetected = false;
readFaultsAndParseIncludeStatementsRecursively(data, gridPos, faults, filenamesWithFaults, &isEditKeywordDetected);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RifEclipseInputFileTools::findFaultByName(const cvf::Collection<RigFault>& faults, const QString& name)
{
for (size_t i = 0; i < faults.size(); i++)
{
if (faults.at(i)->name() == name)
{
return i;
}
}
return cvf::UNDEFINED_SIZE_T;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
qint64 RifEclipseInputFileTools::findKeyword(const QString& keyword, QFile& file, qint64 startPos)
{
QString line;
file.seek(startPos);
do
{
line = file.readLine();
if (line.startsWith("--", Qt::CaseInsensitive))
{
continue;
}
line = line.trimmed();
if (line.startsWith(keyword, Qt::CaseInsensitive))
{
return file.pos();
}
} while (!file.atEnd());
return -1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseInputFileTools::readFaultsAndParseIncludeStatementsRecursively(QFile& file, qint64 startPos, cvf::Collection<RigFault>& faults, std::vector<QString>& filenamesWithFaults, bool* isEditKeywordDetected)
{
QString line;
if (!file.seek(startPos))
{
return false;
}
bool continueParsing = true;
do
{
line = file.readLine();
if (line.startsWith("--", Qt::CaseInsensitive))
{
continue;
}
else if (line.startsWith(editKeyword, Qt::CaseInsensitive))
{
if (isEditKeywordDetected)
{
*isEditKeywordDetected = true;
}
return false;
}
line = line.trimmed();
if (line.startsWith(includeKeyword, Qt::CaseInsensitive))
{
QString nextLine = file.readLine();
int firstQuote = nextLine.indexOf("'");
int lastQuote = nextLine.lastIndexOf("'");
if (!(firstQuote < 0 || lastQuote < 0 || firstQuote == lastQuote))
{
QDir currentFileFolder;
{
QFileInfo fi(file.fileName());
currentFileFolder = fi.absoluteDir();
}
// Read include file name, and both relative and absolute path is supported
QString includeFilename = nextLine.mid(firstQuote + 1, lastQuote - firstQuote - 1);
QFileInfo fi(currentFileFolder, includeFilename);
if (fi.exists())
{
QString absoluteFilename = fi.canonicalFilePath();
QFile includeFile(absoluteFilename);
if (includeFile.open(QFile::ReadOnly))
{
qDebug() << "Found include statement, and start parsing of\n " << absoluteFilename;
if (!readFaultsAndParseIncludeStatementsRecursively(includeFile, 0, faults, filenamesWithFaults, isEditKeywordDetected))
{
qDebug() << "Error when parsing include file : " << absoluteFilename;
}
}
}
}
}
else if (line.startsWith(faultsKeyword, Qt::CaseInsensitive))
{
readFaults(file, file.pos(), faults, isEditKeywordDetected);
filenamesWithFaults.push_back(file.fileName());
}
if (isEditKeywordDetected && *isEditKeywordDetected)
{
continueParsing = false;
}
if (file.atEnd())
{
continueParsing = false;
}
} while (continueParsing);
return true;
}
//--------------------------------------------------------------------------------------------------
/// The file pointer is pointing at the line following the FAULTS keyword.
/// Parse content of this keyword until end of file or
/// end of keyword when a single line with '/' is found
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::readFaults(QFile &data, qint64 filePos, cvf::Collection<RigFault> &faults, bool* isEditKeywordDetected)
{
if (!data.seek(filePos))
{
return;
}
qDebug() << "Reading faults from\n " << data.fileName();
RigFault* fault = NULL;
do
{
QString line = data.readLine();
line = line.trimmed();
if (line.startsWith("--", Qt::CaseInsensitive))
{
// Skip comment lines
continue;
}
else if (line.startsWith("/", Qt::CaseInsensitive))
{
// Detected end of keyword data section
return;
}
else if (line.startsWith(editKeyword, Qt::CaseInsensitive))
{
// End parsing when edit keyword is detected
if (isEditKeywordDetected)
{
*isEditKeywordDetected = true;
}
return;
}
// Replace tab with space to be able to split the string using space as splitter
line.replace("\t", " ");
QStringList entries = line.split(" ", QString::SkipEmptyParts);
if (entries.size() < 8)
{
continue;
}
QString name = entries[0];
name.remove("'");
int i1, i2, j1, j2, k1, k2;
i1 = entries[1].toInt();
i2 = entries[2].toInt();
j1 = entries[3].toInt();
j2 = entries[4].toInt();
k1 = entries[5].toInt();
k2 = entries[6].toInt();
QString faceString = entries[7];
faceString.remove("'");
cvf::StructGridInterface::FaceEnum cellFaceEnum = cvf::StructGridInterface::FaceEnum::fromText(faceString);
cvf::CellRange cellrange(i1 - 1, j1 - 1, k1 - 1, i2 - 1, j2 - 1, k2 - 1); // Adjust from 1-based to 0-based cell indices
if (!(fault && fault->name() == name))
{
if (findFaultByName(faults, name) == cvf::UNDEFINED_SIZE_T)
{
RigFault* newFault = new RigFault;
newFault->setName(name);
faults.push_back(newFault);
}
size_t faultIndex = findFaultByName(faults, name);
if (faultIndex == cvf::UNDEFINED_SIZE_T)
{
CVF_ASSERT(faultIndex != cvf::UNDEFINED_SIZE_T);
continue;
}
fault = faults.at(faultIndex);
}
CVF_ASSERT(fault);
fault->addCellRangeForFace(cellFaceEnum, cellrange);
} while (!data.atEnd());
}

View File

@@ -25,6 +25,7 @@
#include <QString>
#include "RifReaderInterface.h"
#include "RigFault.h"
class RigCaseData;
@@ -52,21 +53,33 @@ public:
RifEclipseInputFileTools();
virtual ~RifEclipseInputFileTools();
static bool openGridFile(const QString& fileName, RigCaseData* eclipseCase);
static bool openGridFile(const QString& fileName, RigCaseData* eclipseCase, bool readFaultData);
// Returns map of assigned resultName and Eclipse Keyword.
static std::map<QString, QString> readProperties(const QString& fileName, RigCaseData* eclipseCase);
static bool readProperty (const QString& fileName, RigCaseData* eclipseCase, const QString& eclipseKeyWord, const QString& resultName );
static bool readPropertyAtFilePosition (const QString& fileName, RigCaseData* eclipseCase, const QString& eclipseKeyWord, qint64 filePos, const QString& resultName );
static void readFaultsInGridSection(const QString& fileName, cvf::Collection<RigFault>& faults, std::vector<QString>& filenamesWithFaults);
static void readFaults(const QString& fileName, cvf::Collection<RigFault>& faults, const std::vector< RifKeywordAndFilePos >& fileKeywords);
static std::vector< RifKeywordAndFilePos > findKeywordsOnFile(const QString &fileName);
static void readFaults(QFile &data, qint64 filePos, cvf::Collection<RigFault> &faults, bool* isEditKeywordDetected);
static void findKeywordsOnFile(const QString &fileName, std::vector< RifKeywordAndFilePos >& keywords);
static const std::vector<QString>& knownPropertyKeywords();
static bool writePropertyToTextFile(const QString& fileName, RigCaseData* eclipseCase, size_t timeStep, const QString& resultName, const QString& eclipseKeyWord);
static bool writeBinaryResultToTextFile(const QString& fileName, RigCaseData* eclipseCase, RifReaderInterface::PorosityModelResultType porosityModel, size_t timeStep, const QString& resultName, const QString& eclipseKeyWord, const double undefinedValue);
static bool readFaultsAndParseIncludeStatementsRecursively(QFile& file, qint64 startPos, cvf::Collection<RigFault>& faults, std::vector<QString>& filenamesWithFaults, bool* isEditKeywordDetected);
private:
static void writeDataToTextFile(QFile* file, const QString& eclipseKeyWord, const std::vector<double>& resultData);
static void findGridKeywordPositions(const QString& filename, qint64* coordPos, qint64* zcornPos, qint64* specgridPos, qint64* actnumPos, qint64* mapaxesPos);
static void findGridKeywordPositions(const std::vector< RifKeywordAndFilePos >& keywords, qint64* coordPos, qint64* zcornPos, qint64* specgridPos, qint64* actnumPos, qint64* mapaxesPos);
static size_t findFaultByName(const cvf::Collection<RigFault>& faults, const QString& name);
static qint64 findKeyword(const QString& keyword, QFile& file, qint64 startPos);
};

View File

@@ -86,7 +86,7 @@ bool RifReaderEclipseInput::open(const QString& fileName, RigCaseData* eclipseCa
bool isOk = false;
if (eclipseCase->mainGrid()->gridPointDimensions() == cvf::Vec3st(0,0,0))
{
isOk = RifEclipseInputFileTools::openGridFile(fileName, eclipseCase);
isOk = RifEclipseInputFileTools::openGridFile(fileName, eclipseCase, isFaultImportEnabled());
}
return isOk;

View File

@@ -33,14 +33,18 @@
#include "ecl_grid.h"
#include "well_state.h"
#include "ecl_kw_magic.h"
#include "ecl_nnc_export.h"
#include "cafProgressInfo.h"
#include <map>
#include "RifEclipseInputFileTools.h"
//--------------------------------------------------------------------------------------------------
/// ECLIPSE cell numbering layout:
/// Lower layer: Upper layer
///
/// Low Depth High Depth
/// Low K High K
/// Shallow Deep
/// 2---3 6---7
/// | | | |
/// 0---1 4---5
@@ -51,17 +55,17 @@
// The indexing conventions for vertices in ECLIPSE
//
// 6-------------7
// /| /|
// / | / |
// / | / |
// 4-------------5 |
// | | | |
// | 2---------|---3
// | / | /
// 2-------------3
// /| /|
// / | / | /j
// / | / | /
// 0-------------1 | *---i
// | | | | |
// | 6---------|---7 |
// | / | / |k
// | / | /
// |/ |/
// 0-------------1
// 4-------------5
// vertex indices
//
// The indexing conventions for vertices in ResInsight
@@ -146,7 +150,7 @@ bool transferGridCellData(RigMainGrid* mainGrid, RigActiveCellInfo* activeCellIn
{
double * point = mainGrid->nodes()[nodeStartIndex + localCellIdx * 8 + cellMappingECLRi[cIdx]].ptr();
ecl_grid_get_corner_xyz1(localEclGrid, localCellIdx, cIdx, &(point[0]), &(point[1]), &(point[2]));
point[2] = -point[2];
point[2] = -point[2]; // Flipping Z making depth become negative z values
cell.cornerIndices()[cIdx] = nodeStartIndex + localCellIdx*8 + cIdx;
}
@@ -241,6 +245,7 @@ bool RifReaderEclipseOutput::transferGeometry(const ecl_grid_type* mainEclGrid,
CVF_ASSERT(activeCellInfo && fractureActiveCellInfo);
RigMainGrid* mainGrid = eclipseCase->mainGrid();
CVF_ASSERT(mainGrid);
{
cvf::Vec3st gridPointDim(0,0,0);
gridPointDim.x() = ecl_grid_get_nx(mainEclGrid) + 1;
@@ -249,6 +254,10 @@ bool RifReaderEclipseOutput::transferGeometry(const ecl_grid_type* mainEclGrid,
mainGrid->setGridPointDimensions(gridPointDim);
}
// std::string mainGridName = ecl_grid_get_name(mainEclGrid);
// ERT returns file path to grid file as name for main grid
mainGrid->setGridName("Main grid");
// Get and set grid and lgr metadata
size_t totalCellCount = static_cast<size_t>(ecl_grid_get_global_size(mainEclGrid));
@@ -368,17 +377,71 @@ bool RifReaderEclipseOutput::open(const QString& fileName, RigCaseData* eclipseC
progInfo.setProgressDescription("Transferring grid geometry");
if (!transferGeometry(mainEclGrid, eclipseCase)) return false;
progInfo.incrementProgress();
progInfo.setProgressDescription("Reading faults");
progInfo.setNextProgressIncrement(10);
if (isFaultImportEnabled())
{
if (this->filenamesWithFaults().size() > 0)
{
cvf::Collection<RigFault> faults;
std::vector< RifKeywordAndFilePos > fileKeywords;
std::vector<QString> filenamesWithFaults;
for (size_t i = 0; i < this->filenamesWithFaults().size(); i++)
{
QString faultFilename = this->filenamesWithFaults()[i];
RifEclipseInputFileTools::readFaults(faultFilename, faults, fileKeywords);
}
RigMainGrid* mainGrid = eclipseCase->mainGrid();
mainGrid->setFaults(faults);
}
else
{
foreach (QString fname, fileSet)
{
if (fname.endsWith(".DATA"))
{
cvf::Collection<RigFault> faults;
std::vector<QString> filenamesWithFaults;
RifEclipseInputFileTools::readFaultsInGridSection(fname, faults, filenamesWithFaults);
RigMainGrid* mainGrid = eclipseCase->mainGrid();
mainGrid->setFaults(faults);
std::unique(filenamesWithFaults.begin(), filenamesWithFaults.end());
this->setFilenamesWithFaults(filenamesWithFaults);
}
}
}
}
progInfo.incrementProgress();
m_eclipseCase = eclipseCase;
progInfo.setProgressDescription("Reading Result index");
progInfo.setNextProgressIncrement(60);
// Build results meta data
progInfo.setProgressDescription("Reading Result index");
progInfo.setNextProgressIncrement(25);
buildMetaData();
progInfo.incrementProgress();
progInfo.setProgressDescription("Reading NNC data");
progInfo.setNextProgressIncrement(5);
transferNNCData(mainEclGrid, m_ecl_init_file, eclipseCase->mainGrid());
progInfo.incrementProgress();
progInfo.setProgressDescription("Processing NNC data");
progInfo.setNextProgressIncrement(20);
eclipseCase->mainGrid()->nncData()->processConnections( *(eclipseCase->mainGrid()));
progInfo.incrementProgress();
progInfo.setNextProgressIncrement(8);
progInfo.setProgressDescription("Reading Well information");
readWellCells(mainEclGrid);
@@ -390,6 +453,36 @@ bool RifReaderEclipseOutput::open(const QString& fileName, RigCaseData* eclipseC
return true;
}
void RifReaderEclipseOutput::transferNNCData( const ecl_grid_type * mainEclGrid , const ecl_file_type * init_file, RigMainGrid * mainGrid)
{
if (!m_ecl_init_file ) return;
CVF_ASSERT(mainEclGrid && mainGrid);
// Get the data from ERT
int numNNC = ecl_nnc_export_get_size( mainEclGrid );
ecl_nnc_type * eclNNCData= new ecl_nnc_type[numNNC];
ecl_nnc_export( mainEclGrid , init_file , eclNNCData);
// Transform to our own datastructures
//cvf::Trace::show("Reading NNC. Count: " + cvf::String(numNNC));
mainGrid->nncData()->connections().resize(numNNC);
for (int nIdx = 0; nIdx < numNNC; ++nIdx)
{
RigGridBase* grid1 = mainGrid->gridByIndex(eclNNCData[nIdx].grid_nr1);
mainGrid->nncData()->connections()[nIdx].m_c1GlobIdx = grid1->globalGridCellIndex(eclNNCData[nIdx].global_index1);
RigGridBase* grid2 = mainGrid->gridByIndex(eclNNCData[nIdx].grid_nr2);
mainGrid->nncData()->connections()[nIdx].m_c2GlobIdx = grid2->globalGridCellIndex(eclNNCData[nIdx].global_index2);
mainGrid->nncData()->connections()[nIdx].m_transmissibility = eclNNCData[nIdx].trans;
}
delete[] eclNNCData;
}
//--------------------------------------------------------------------------------------------------
///

View File

@@ -70,6 +70,8 @@ private:
bool openDynamicAccess();
void extractResultValuesBasedOnPorosityModel(PorosityModelResultType matrixOrFracture, std::vector<double>* values, const std::vector<double>& fileValues);
void transferNNCData( const ecl_grid_type * mainEclGrid , const ecl_file_type * init_file,
RigMainGrid * mainGrid);
RifEclipseRestartDataAccess* createDynamicResultsAccess();

View File

@@ -44,8 +44,11 @@ public:
};
public:
RifReaderInterface() {}
virtual ~RifReaderInterface() {}
RifReaderInterface() { m_readFaultData = false; }
virtual ~RifReaderInterface() {}
void readFaultData(bool readFaultData) { m_readFaultData = readFaultData; }
bool isFaultImportEnabled() { return m_readFaultData; }
virtual bool open(const QString& fileName, RigCaseData* eclipseCase) = 0;
virtual void close() = 0;
@@ -53,5 +56,13 @@ public:
virtual bool staticResult(const QString& result, PorosityModelResultType matrixOrFracture, std::vector<double>* values) = 0;
virtual bool dynamicResult(const QString& result, PorosityModelResultType matrixOrFracture, size_t stepIndex, std::vector<double>* values) = 0;
virtual std::vector<QDateTime> timeSteps() { std::vector<QDateTime> timeSteps; return timeSteps; }
virtual std::vector<QDateTime> timeSteps() { std::vector<QDateTime> timeSteps; return timeSteps; }
void setFilenamesWithFaults(const std::vector<QString>& filenames) { m_filenamesWithFaults = filenames; }
std::vector<QString> filenamesWithFaults() { return m_filenamesWithFaults; }
private:
std::vector<QString> m_filenamesWithFaults;
bool m_readFaultData;
};

View File

@@ -6,11 +6,17 @@ endif()
set (SOURCE_GROUP_HEADER_FILES
${CEE_CURRENT_LIST_DIR}RivCellEdgeEffectGenerator.h
${CEE_CURRENT_LIST_DIR}RivColorTableArray.h
${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}RivReservoirPartMgr.h
${CEE_CURRENT_LIST_DIR}RivReservoirViewPartMgr.h
${CEE_CURRENT_LIST_DIR}RivPipeGeometryGenerator.h
${CEE_CURRENT_LIST_DIR}RivReservoirFaultsPartMgr.h
${CEE_CURRENT_LIST_DIR}RivReservoirPipesPartMgr.h
${CEE_CURRENT_LIST_DIR}RivSourceInfo.h
${CEE_CURRENT_LIST_DIR}RivWellPathPartMgr.h
${CEE_CURRENT_LIST_DIR}RivWellPathCollectionPartMgr.h
${CEE_CURRENT_LIST_DIR}RivWellPipesPartMgr.h
@@ -19,11 +25,17 @@ ${CEE_CURRENT_LIST_DIR}RivWellHeadPartMgr.h
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}RivGridPartMgr.cpp
${CEE_CURRENT_LIST_DIR}RivReservoirFaultsPartMgr.cpp
${CEE_CURRENT_LIST_DIR}RivReservoirPartMgr.cpp
${CEE_CURRENT_LIST_DIR}RivReservoirViewPartMgr.cpp
${CEE_CURRENT_LIST_DIR}RivPipeGeometryGenerator.cpp
${CEE_CURRENT_LIST_DIR}RivReservoirPipesPartMgr.cpp
${CEE_CURRENT_LIST_DIR}RivSourceInfo.cpp
${CEE_CURRENT_LIST_DIR}RivWellPathPartMgr.cpp
${CEE_CURRENT_LIST_DIR}RivWellPathCollectionPartMgr.cpp
${CEE_CURRENT_LIST_DIR}RivWellPipesPartMgr.cpp

View File

@@ -345,7 +345,7 @@ void CellEdgeEffectGenerator::updateForShaderBasedRendering(cvf::Effect* effect)
QTextStream in(&data);
QString data = in.readAll();
cvf::String cvfString = cvfqt::Utils::fromQString(data);
cvf::String cvfString = cvfqt::Utils::toString(data);
shaderGen.addFragmentCode(cvfString);
}
@@ -358,7 +358,7 @@ void CellEdgeEffectGenerator::updateForShaderBasedRendering(cvf::Effect* effect)
QTextStream in(&data);
QString data = in.readAll();
cvf::String cvfString = cvfqt::Utils::fromQString(data);
cvf::String cvfString = cvfqt::Utils::toString(data);
shaderGen.addVertexCode(cvfString);
}
@@ -433,7 +433,7 @@ void CellEdgeEffectGenerator::updateForShaderBasedRendering(cvf::Effect* effect)
//--------------------------------------------------------------------------------------------------
void CellEdgeEffectGenerator::updateForFixedFunctionRendering(cvf::Effect* effect) const
{
caf::SurfaceEffectGenerator surfaceGen(cvf::Color4f(cvf::Color3f::CRIMSON), true);
caf::SurfaceEffectGenerator surfaceGen(cvf::Color4f(cvf::Color3f::CRIMSON), caf::PO_1);
surfaceGen.updateEffect(effect);
}

View File

@@ -0,0 +1,43 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RivColorTableArray.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::Color3fArray> RivColorTableArray::colorTableArray()
{
cvf::ref<cvf::Color3fArray> partColors = new cvf::Color3fArray();
partColors->reserve(10);
partColors->add(cvf::Color3f(101.0f/255, 132.0f/255, 96.0f/255)); // Dark green
partColors->add(cvf::Color3f(255.0f/255, 131.0f/255, 140.0f/255)); // Old pink
partColors->add(cvf::Color3f(210.0f/255, 176.0f/255, 112.0f/255)); // Light Brown
partColors->add(cvf::Color3f(140.0f/255, 171.0f/255, 238.0f/255)); // Light gray blue
partColors->add(cvf::Color3f(255.0f/255, 205.0f/255, 131.0f/255)); // Peach
partColors->add(cvf::Color3f(220.0f/255, 212.0f/255, 166.0f/255)); // Dark off white
partColors->add(cvf::Color3f(130.0f/255, 255.0f/255, 120.0f/255)); // Light green
partColors->add(cvf::Color3f(166.0f/255, 220.0f/255, 215.0f/255)); // Light gray torquise
partColors->add(cvf::Color3f(168.0f/255, 220.0f/255, 166.0f/255)); // Light gray green
partColors->add(cvf::Color3f(255.0f/255, 64.0f/255, 236.0f/255)); // Magneta
return partColors;
}

View File

@@ -0,0 +1,29 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfBase.h"
#include "cvfObject.h"
#include "cvfArray.h"
class RivColorTableArray
{
public:
static cvf::ref<cvf::Color3fArray> colorTableArray();
};

View File

@@ -0,0 +1,287 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RivFaultGeometryGenerator.h"
#include <cmath>
#include "cvfDrawableGeo.h"
#include "cvfPrimitiveSetIndexedUInt.h"
#include "cvfOutlineEdgeExtractor.h"
#include "cvfStructGridScalarDataAccess.h"
#include "cvfScalarMapper.h"
#include "RigFault.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivFaultGeometryGenerator::RivFaultGeometryGenerator(const cvf::StructGridInterface* grid, const RigFault* fault, bool computeNativeFaultFaces)
: m_grid(grid),
m_fault(fault),
m_computeNativeFaultFaces(computeNativeFaultFaces)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivFaultGeometryGenerator::~RivFaultGeometryGenerator()
{
}
//--------------------------------------------------------------------------------------------------
/// Generate surface drawable geo from the specified region
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableGeo> RivFaultGeometryGenerator::generateSurface()
{
computeArrays();
CVF_ASSERT(m_vertices.notNull());
if (m_vertices->size() == 0) return NULL;
cvf::ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;
geo->setFromQuadVertexArray(m_vertices.p());
return geo;
}
//--------------------------------------------------------------------------------------------------
/// Generates simplified mesh as line drawing
/// Must call generateSurface first
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableGeo> RivFaultGeometryGenerator::createMeshDrawable()
{
if (!(m_vertices.notNull() && m_vertices->size() != 0)) return NULL;
cvf::ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;
geo->setVertexArray(m_vertices.p());
cvf::ref<cvf::UIntArray> indices = lineIndicesFromQuadVertexArray(m_vertices.p());
cvf::ref<cvf::PrimitiveSetIndexedUInt> prim = new cvf::PrimitiveSetIndexedUInt(cvf::PT_LINES);
prim->setIndices(indices.p());
geo->addPrimitiveSet(prim.p());
return geo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableGeo> RivFaultGeometryGenerator::createOutlineMeshDrawable(double creaseAngle)
{
if (!(m_vertices.notNull() && m_vertices->size() != 0)) return NULL;
cvf::OutlineEdgeExtractor ee(creaseAngle, *m_vertices);
cvf::ref<cvf::UIntArray> indices = lineIndicesFromQuadVertexArray(m_vertices.p());
ee.addPrimitives(4, *indices);
cvf::ref<cvf::UIntArray> lineIndices = ee.lineIndices();
if (lineIndices->size() == 0)
{
return NULL;
}
cvf::ref<cvf::PrimitiveSetIndexedUInt> prim = new cvf::PrimitiveSetIndexedUInt(cvf::PT_LINES);
prim->setIndices(lineIndices.p());
cvf::ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;
geo->setVertexArray(m_vertices.p());
geo->addPrimitiveSet(prim.p());
return geo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::UIntArray> RivFaultGeometryGenerator::lineIndicesFromQuadVertexArray(const cvf::Vec3fArray* vertexArray)
{
CVF_ASSERT(vertexArray);
size_t numVertices = vertexArray->size();
int numQuads = static_cast<int>(numVertices/4);
CVF_ASSERT(numVertices%4 == 0);
cvf::ref<cvf::UIntArray> indices = new cvf::UIntArray;
indices->resize(numQuads*8);
#pragma omp parallel for
for (int i = 0; i < numQuads; i++)
{
int idx = 8*i;
indices->set(idx + 0, i*4 + 0);
indices->set(idx + 1, i*4 + 1);
indices->set(idx + 2, i*4 + 1);
indices->set(idx + 3, i*4 + 2);
indices->set(idx + 4, i*4 + 2);
indices->set(idx + 5, i*4 + 3);
indices->set(idx + 6, i*4 + 3);
indices->set(idx + 7, i*4 + 0);
}
return indices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultGeometryGenerator::computeArrays()
{
std::vector<cvf::Vec3f> vertices;
m_quadsToGridCells.clear();
m_quadsToFace.clear();
cvf::Vec3d offset = m_grid->displayModelOffset();
const std::vector<RigFault::FaultFace>& faultFaces = m_fault->faultFaces();
#pragma omp parallel for
for (int fIdx = 0; fIdx < static_cast<int>(faultFaces.size()); fIdx++)
{
size_t cellIndex = faultFaces[fIdx].m_nativeGlobalCellIndex;
cvf::StructGridInterface::FaceType face = faultFaces[fIdx].m_nativeFace;
if (!m_computeNativeFaultFaces)
{
cellIndex = faultFaces[fIdx].m_oppositeGlobalCellIndex;
face = cvf::StructGridInterface::oppositeFace(faultFaces[fIdx].m_nativeFace);
}
if (!(*m_cellVisibility)[cellIndex]) continue;
cvf::Vec3d cornerVerts[8];
m_grid->cellCornerVertices(cellIndex, cornerVerts);
cvf::ubyte faceConn[4];
m_grid->cellFaceVertexIndices(face, faceConn);
// Critical section to avoid two threads accessing the arrays at the same time.
#pragma omp critical
{
int n;
for (n = 0; n < 4; n++)
{
vertices.push_back(cvf::Vec3f(cornerVerts[faceConn[n]] - offset));
}
// Keep track of the source cell index per quad
m_quadsToGridCells.push_back(cellIndex);
m_quadsToFace.push_back(face);
}
}
m_vertices = new cvf::Vec3fArray;
m_vertices->assign(vertices);
}
//--------------------------------------------------------------------------------------------------
/// Calculates the texture coordinates in a "nearly" one dimensional texture.
/// Undefined values are coded with a y-texture coordinate value of 1.0 instead of the normal 0.5
//--------------------------------------------------------------------------------------------------
void RivFaultGeometryGenerator::textureCoordinates(cvf::Vec2fArray* textureCoords, const cvf::StructGridScalarDataAccess* dataAccessObject, const cvf::ScalarMapper* mapper) const
{
if (!dataAccessObject) return;
size_t numVertices = m_quadsToGridCells.size()*4;
textureCoords->resize(numVertices);
cvf::Vec2f* rawPtr = textureCoords->ptr();
double cellScalarValue;
cvf::Vec2f texCoord;
#pragma omp parallel for private(texCoord, cellScalarValue)
for (int i = 0; i < static_cast<int>(m_quadsToGridCells.size()); i++)
{
cellScalarValue = dataAccessObject->cellScalar(m_quadsToGridCells[i]);
texCoord = mapper->mapToTextureCoord(cellScalarValue);
if (cellScalarValue == HUGE_VAL || cellScalarValue != cellScalarValue) // a != a is true for NAN's
{
texCoord[1] = 1.0f;
}
size_t j;
for (j = 0; j < 4; j++)
{
rawPtr[i*4 + j] = texCoord;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::Array<size_t> > RivFaultGeometryGenerator::triangleToSourceGridCellMap() const
{
cvf::ref<cvf::Array<size_t> > triangles = new cvf::Array<size_t>(2*m_quadsToGridCells.size());
#pragma omp parallel for
for (int i = 0; i < static_cast<int>(m_quadsToGridCells.size()); i++)
{
triangles->set(i*2, m_quadsToGridCells[i]);
triangles->set(i*2+1, m_quadsToGridCells[i]);
}
return triangles;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::Array<cvf::StructGridInterface::FaceType> > RivFaultGeometryGenerator::triangleToFaceType() const
{
cvf::ref<cvf::Array<cvf::StructGridInterface::FaceType> > triangles = new cvf::Array<cvf::StructGridInterface::FaceType>(2*m_quadsToFace.size());
#pragma omp parallel for
for (int i = 0; i < static_cast<int>(m_quadsToFace.size()); i++)
{
triangles->set(i*2, m_quadsToFace[i]);
triangles->set(i*2+1, m_quadsToFace[i]);
}
return triangles;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultGeometryGenerator::setCellVisibility(const cvf::UByteArray* cellVisibility)
{
m_cellVisibility = cellVisibility;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<size_t>& RivFaultGeometryGenerator::quadToGridCellIndices() const
{
return m_quadsToGridCells;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<cvf::StructGridInterface::FaceType>& RivFaultGeometryGenerator::quadToFace() const
{
return m_quadsToFace;
}

View File

@@ -0,0 +1,87 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfBase.h"
#include "cvfObject.h"
#include "cvfStructGridGeometryGenerator.h"
#include "cvfCellRange.h"
namespace cvf
{
class StructGridInterface;
class ModelBasicList;
class Transform;
class Part;
}
class RigFault;
//==================================================================================================
///
///
//==================================================================================================
class RivFaultGeometryGenerator : public cvf::Object
{
public:
RivFaultGeometryGenerator(const cvf::StructGridInterface* grid, const RigFault* fault, bool computeNativeFaultFaces);
~RivFaultGeometryGenerator();
void setCellVisibility(const cvf::UByteArray* cellVisibilities );
void textureCoordinates(cvf::Vec2fArray* textureCoords,
const cvf::StructGridScalarDataAccess* dataAccessObject,
const cvf::ScalarMapper* mapper) const;
// Mapping between cells and geometry
cvf::ref<cvf::Array<size_t> > triangleToSourceGridCellMap() const;
cvf::ref<cvf::Array<cvf::StructGridInterface::FaceType> > triangleToFaceType() const;
const std::vector<size_t>& quadToGridCellIndices() const;
const std::vector<cvf::StructGridInterface::FaceType>& quadToFace() const;
// Generated geometry
cvf::ref<cvf::DrawableGeo> generateSurface();
cvf::ref<cvf::DrawableGeo> createMeshDrawable();
cvf::ref<cvf::DrawableGeo> createOutlineMeshDrawable(double creaseAngle);
private:
static cvf::ref<cvf::UIntArray> lineIndicesFromQuadVertexArray(const cvf::Vec3fArray* vertexArray);
void computeArrays();
private:
// Input
cvf::cref<cvf::StructGridInterface> m_grid;
cvf::cref<RigFault> m_fault;
cvf::cref<cvf::UByteArray> m_cellVisibility;
bool m_computeNativeFaultFaces;
// Created arrays
cvf::ref<cvf::Vec3fArray> m_vertices;
// Mappings
std::vector<size_t> m_triangleIndexToGridCellIndex;
std::vector<size_t> m_quadsToGridCells;
std::vector<cvf::StructGridInterface::FaceType> m_quadsToFace;
std::vector<cvf::StructGridInterface::FaceType> m_triangleToFace;
};

View File

@@ -0,0 +1,728 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RivFaultPartMgr.h"
#include "cvfPart.h"
#include "cafEffectGenerator.h"
#include "cvfStructGrid.h"
#include "cvfDrawableGeo.h"
#include "cvfModelBasicList.h"
#include "RivCellEdgeEffectGenerator.h"
#include "RimReservoirView.h"
#include "RimResultSlot.h"
#include "RimCellEdgeResultSlot.h"
#include "RigCaseCellResultsData.h"
#include "RigCaseData.h"
#include "RiaApplication.h"
#include "RiaPreferences.h"
#include "RimCase.h"
#include "RimWellCollection.h"
#include "cafPdmFieldCvfMat4d.h"
#include "cafPdmFieldCvfColor.h"
#include "RimCellRangeFilterCollection.h"
#include "RimCellPropertyFilterCollection.h"
#include "Rim3dOverlayInfoConfig.h"
#include "RimReservoirCellResultsCacher.h"
#include "cvfDrawableText.h"
#include "cvfqtUtils.h"
#include "cvfPrimitiveSetIndexedUInt.h"
#include "cvfPrimitiveSetDirect.h"
#include "RivGridPartMgr.h"
#include "cvfRenderStateDepth.h"
#include "RivSourceInfo.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivFaultPartMgr::RivFaultPartMgr(const RigGridBase* grid, const RimFaultCollection* rimFaultCollection, const RimFault* rimFault)
: m_grid(grid),
m_rimFaultCollection(rimFaultCollection),
m_rimFault(rimFault),
m_opacityLevel(1.0f),
m_defaultColor(cvf::Color3::WHITE)
{
cvf::ref< cvf::Array<size_t> > connIdxes = new cvf::Array<size_t>;
connIdxes->assign(rimFault->faultGeometry()->connectionIndices());
m_nativeFaultGenerator = new RivFaultGeometryGenerator(grid, rimFault->faultGeometry(), true);
m_oppositeFaultGenerator = new RivFaultGeometryGenerator(grid, rimFault->faultGeometry(), false);
m_NNCGenerator = new RivNNCGeometryGenerator(grid->mainGrid()->nncData(), grid->mainGrid()->displayModelOffset(), connIdxes.p());
m_nativeFaultFacesTextureCoords = new cvf::Vec2fArray;
m_oppositeFaultFacesTextureCoords = new cvf::Vec2fArray;
m_NNCTextureCoords = new cvf::Vec2fArray;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultPartMgr::setCellVisibility(cvf::UByteArray* cellVisibilities)
{
m_nativeFaultGenerator->setCellVisibility(cellVisibilities);
m_oppositeFaultGenerator->setCellVisibility(cellVisibilities);
m_NNCGenerator->setCellVisibility(cellVisibilities, m_grid.p());
generatePartGeometry();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultPartMgr::applySingleColorEffect()
{
m_defaultColor = m_rimFault->faultColor();
this->updatePartEffect();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultPartMgr::updateCellResultColor(size_t timeStepIndex, RimResultSlot* cellResultSlot)
{
CVF_ASSERT(cellResultSlot);
updateNNCColors(cellResultSlot);
size_t scalarSetIndex = cellResultSlot->gridScalarIndex();
const cvf::ScalarMapper* mapper = cellResultSlot->legendConfig()->scalarMapper();
// If the result is static, only read that.
size_t resTimeStepIdx = timeStepIndex;
if (cellResultSlot->hasStaticResult()) resTimeStepIdx = 0;
RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultSlot->porosityModel());
RigCaseData* eclipseCase = cellResultSlot->reservoirView()->eclipseCase()->reservoirData();
cvf::ref<cvf::StructGridScalarDataAccess> 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)
{
const std::vector<cvf::StructGridInterface::FaceType>& quadsToFaceTypes = m_nativeFaultGenerator->quadToFace();
const std::vector<size_t>& quadsToGridCells = m_nativeFaultGenerator->quadToGridCellIndices();
cvf::Vec2fArray* textureCoords = m_nativeFaultFacesTextureCoords.p();
RivTransmissibilityColorMapper::updateCombinedTransmissibilityTextureCoordinates(cellResultSlot, m_grid.p(), textureCoords, quadsToFaceTypes, quadsToGridCells);
}
else
{
m_nativeFaultGenerator->textureCoordinates(m_nativeFaultFacesTextureCoords.p(), dataAccessObject.p(), mapper);
}
if (m_opacityLevel < 1.0f )
{
const std::vector<cvf::ubyte>& isWellPipeVisible = cellResultSlot->reservoirView()->wellCollection()->isWellPipesVisible(timeStepIndex);
cvf::ref<cvf::UIntArray> gridCellToWellindexMap = eclipseCase->gridCellToWellIndex(m_grid->gridIndex());
const std::vector<size_t>& quadsToGridCells = m_nativeFaultGenerator->quadToGridCellIndices();
for(size_t i = 0; i < m_nativeFaultFacesTextureCoords->size(); ++i)
{
if ((*m_nativeFaultFacesTextureCoords)[i].y() == 1.0f) continue; // Do not touch undefined values
size_t quadIdx = i/4;
size_t cellIndex = quadsToGridCells[quadIdx];
cvf::uint wellIndex = gridCellToWellindexMap->get(cellIndex);
if (wellIndex != cvf::UNDEFINED_UINT)
{
if ( !isWellPipeVisible[wellIndex])
{
(*m_nativeFaultFacesTextureCoords)[i].y() = 0; // Set the Y texture coordinate to the opaque line in the texture
}
}
}
}
cvf::DrawableGeo* dg = dynamic_cast<cvf::DrawableGeo*>(m_nativeFaultFaces->drawable());
if (dg) dg->setTextureCoordArray(m_nativeFaultFacesTextureCoords.p());
cvf::ref<cvf::Effect> scalarEffect = cellResultEffect(mapper, caf::PO_1);
m_nativeFaultFaces->setEffect(scalarEffect.p());
}
if (m_oppositeFaultFaces.notNull())
{
if (cellResultSlot->resultVariable().compare(RimDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0)
{
const std::vector<cvf::StructGridInterface::FaceType>& quadsToFaceTypes = m_oppositeFaultGenerator->quadToFace();
const std::vector<size_t>& quadsToGridCells = m_oppositeFaultGenerator->quadToGridCellIndices();
cvf::Vec2fArray* textureCoords = m_oppositeFaultFacesTextureCoords.p();
RivTransmissibilityColorMapper::updateCombinedTransmissibilityTextureCoordinates(cellResultSlot, m_grid.p(), textureCoords, quadsToFaceTypes, quadsToGridCells);
}
else
{
m_oppositeFaultGenerator->textureCoordinates(m_oppositeFaultFacesTextureCoords.p(), dataAccessObject.p(), mapper);
}
if (m_opacityLevel < 1.0f )
{
const std::vector<cvf::ubyte>& isWellPipeVisible = cellResultSlot->reservoirView()->wellCollection()->isWellPipesVisible(timeStepIndex);
cvf::ref<cvf::UIntArray> gridCellToWellindexMap = eclipseCase->gridCellToWellIndex(m_grid->gridIndex());
const std::vector<size_t>& quadsToGridCells = m_oppositeFaultGenerator->quadToGridCellIndices();
for(size_t i = 0; i < m_oppositeFaultFacesTextureCoords->size(); ++i)
{
if ((*m_oppositeFaultFacesTextureCoords)[i].y() == 1.0f) continue; // Do not touch undefined values
size_t quadIdx = i/4;
size_t cellIndex = quadsToGridCells[quadIdx];
cvf::uint wellIndex = gridCellToWellindexMap->get(cellIndex);
if (wellIndex != cvf::UNDEFINED_UINT)
{
if ( !isWellPipeVisible[wellIndex])
{
(*m_oppositeFaultFacesTextureCoords)[i].y() = 0; // Set the Y texture coordinate to the opaque line in the texture
}
}
}
}
cvf::DrawableGeo* dg = dynamic_cast<cvf::DrawableGeo*>(m_oppositeFaultFaces->drawable());
if (dg) dg->setTextureCoordArray(m_oppositeFaultFacesTextureCoords.p());
// Use a different offset than native fault faces to avoid z-fighting
cvf::ref<cvf::Effect> scalarEffect = cellResultEffect(mapper, caf::PO_2);
m_oppositeFaultFaces->setEffect(scalarEffect.p());
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultPartMgr::updateCellEdgeResultColor(size_t timeStepIndex, RimResultSlot* cellResultSlot, RimCellEdgeResultSlot* cellEdgeResultSlot)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultPartMgr::generatePartGeometry()
{
const int priFaultGeo = 1;
const int priNncGeo = 2;
const int priMesh = 3;
bool useBufferObjects = true;
// Surface geometry
{
cvf::ref<cvf::DrawableGeo> geo = m_nativeFaultGenerator->generateSurface();
if (geo.notNull())
{
geo->computeNormals();
if (useBufferObjects)
{
geo->setRenderMode(cvf::DrawableGeo::BUFFER_OBJECT);
}
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName("Grid " + cvf::String(static_cast<int>(m_grid->gridIndex())));
part->setId(m_grid->gridIndex()); // !! For now, use grid index as part ID (needed for pick info)
part->setDrawable(geo.p());
// Set mapping from triangle face index to cell index
cvf::ref<RivSourceInfo> si = new RivSourceInfo;
si->m_cellIndices = m_nativeFaultGenerator->triangleToSourceGridCellMap().p();
si->m_faceTypes = m_nativeFaultGenerator->triangleToFaceType().p();
part->setSourceInfo(si.p());
part->updateBoundingBox();
part->setEnableMask(faultBit);
part->setPriority(priFaultGeo);
m_nativeFaultFaces = part;
}
}
// Mesh geometry
{
cvf::ref<cvf::DrawableGeo> geoMesh = m_nativeFaultGenerator->createMeshDrawable();
if (geoMesh.notNull())
{
if (useBufferObjects)
{
geoMesh->setRenderMode(cvf::DrawableGeo::BUFFER_OBJECT);
}
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName("Grid mesh" + cvf::String(static_cast<int>(m_grid->gridIndex())));
part->setDrawable(geoMesh.p());
part->updateBoundingBox();
part->setEnableMask(meshFaultBit);
part->setPriority(priMesh);
m_nativeFaultGridLines = part;
}
}
// Surface geometry
{
cvf::ref<cvf::DrawableGeo> geo = m_oppositeFaultGenerator->generateSurface();
if (geo.notNull())
{
geo->computeNormals();
if (useBufferObjects)
{
geo->setRenderMode(cvf::DrawableGeo::BUFFER_OBJECT);
}
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName("Grid " + cvf::String(static_cast<int>(m_grid->gridIndex())));
part->setId(m_grid->gridIndex()); // !! For now, use grid index as part ID (needed for pick info)
part->setDrawable(geo.p());
// Set mapping from triangle face index to cell index
cvf::ref<RivSourceInfo> si = new RivSourceInfo;
si->m_cellIndices = m_oppositeFaultGenerator->triangleToSourceGridCellMap().p();
si->m_faceTypes = m_oppositeFaultGenerator->triangleToFaceType().p();
part->setSourceInfo(si.p());
part->updateBoundingBox();
part->setEnableMask(faultBit);
part->setPriority(priFaultGeo);
m_oppositeFaultFaces = part;
}
}
// Mesh geometry
{
cvf::ref<cvf::DrawableGeo> geoMesh = m_oppositeFaultGenerator->createMeshDrawable();
if (geoMesh.notNull())
{
if (useBufferObjects)
{
geoMesh->setRenderMode(cvf::DrawableGeo::BUFFER_OBJECT);
}
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName("Grid mesh" + cvf::String(static_cast<int>(m_grid->gridIndex())));
part->setDrawable(geoMesh.p());
part->updateBoundingBox();
part->setEnableMask(meshFaultBit);
part->setPriority(priMesh);
m_oppositeFaultGridLines = part;
}
}
{
cvf::ref<cvf::DrawableGeo> geo = m_NNCGenerator->generateSurface();
if (geo.notNull())
{
geo->computeNormals();
if (useBufferObjects)
{
geo->setRenderMode(cvf::DrawableGeo::BUFFER_OBJECT);
}
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName("NNC in Fault. Grid " + cvf::String(static_cast<int>(m_grid->gridIndex())));
part->setId(m_grid->gridIndex()); // !! For now, use grid index as part ID (needed for pick info)
part->setDrawable(geo.p());
// Set mapping from triangle face index to cell index
cvf::ref<RivSourceInfo> si = new RivSourceInfo;
si->m_NNCIndices = m_NNCGenerator->triangleToNNCIndex().p();
part->setSourceInfo(si.p());
part->updateBoundingBox();
part->setEnableMask(faultBit);
part->setPriority(priNncGeo);
m_NNCFaces = part;
}
}
createLabelWithAnchorLine(m_nativeFaultFaces.p());
updatePartEffect();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultPartMgr::updatePartEffect()
{
// Set default effect
caf::SurfaceEffectGenerator geometryEffgen(m_defaultColor, caf::PO_1);
geometryEffgen.setCullBackfaces(faceCullingMode());
cvf::ref<cvf::Effect> geometryOnlyEffect = geometryEffgen.generateEffect();
if (m_nativeFaultFaces.notNull())
{
m_nativeFaultFaces->setEffect(geometryOnlyEffect.p());
}
if (m_oppositeFaultFaces.notNull())
{
m_oppositeFaultFaces->setEffect(geometryOnlyEffect.p());
}
updateNNCColors(NULL);
// Update mesh colors as well, in case of change
RiaPreferences* prefs = RiaApplication::instance()->preferences();
cvf::ref<cvf::Effect> eff;
caf::MeshEffectGenerator faultEffGen(prefs->defaultFaultGridLineColors());
eff = faultEffGen.generateEffect();
if (m_nativeFaultGridLines.notNull())
{
m_nativeFaultGridLines->setEffect(eff.p());
}
if (m_oppositeFaultGridLines.notNull())
{
m_oppositeFaultGridLines->setEffect(eff.p());
}
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);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultPartMgr::createLabelWithAnchorLine(const cvf::Part* part)
{
m_faultLabelPart = NULL;
m_faultLabelLinePart = NULL;
if (!part) return;
cvf::BoundingBox bb = part->boundingBox();
cvf::Vec3d bbTopCenter = bb.center();
bbTopCenter.z() = bb.max().z();
const cvf::DrawableGeo* geo = dynamic_cast<const cvf::DrawableGeo*>(part->drawable());
// Find closest vertex to top of bounding box.
// Will be recomputed when filter changes, to make sure the label is always visible
// for any filter combination
cvf::Vec3f faultVertexToAttachLabel = findClosestVertex(cvf::Vec3f(bbTopCenter), geo->vertexArray());
cvf::Vec3f labelPosition = faultVertexToAttachLabel;
labelPosition.z() += bb.extent().z() / 2;
// Fault label
{
cvf::Font* standardFont = RiaApplication::instance()->standardFont();
cvf::ref<cvf::DrawableText> drawableText = new cvf::DrawableText;
drawableText->setFont(standardFont);
drawableText->setCheckPosVisible(false);
drawableText->setDrawBorder(false);
drawableText->setDrawBackground(false);
drawableText->setVerticalAlignment(cvf::TextDrawer::CENTER);
cvf::Color3f defWellLabelColor = RiaApplication::instance()->preferences()->defaultWellLabelColor();
{
std::vector<RimFaultCollection*> parentObjects;
m_rimFault->parentObjectsOfType(parentObjects);
if (parentObjects.size() > 0)
{
defWellLabelColor = parentObjects[0]->faultLabelColor();;
}
}
drawableText->setTextColor(defWellLabelColor);
cvf::String cvfString = cvfqt::Utils::toString(m_rimFault->name());
cvf::Vec3f textCoord(labelPosition);
double characteristicCellSize = bb.extent().z() / 20;
textCoord.z() += characteristicCellSize;
drawableText->addText(cvfString, textCoord);
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName("RivFaultPart : text " + cvfString);
part->setDrawable(drawableText.p());
cvf::ref<cvf::Effect> eff = new cvf::Effect;
part->setEffect(eff.p());
part->setPriority(1000);
m_faultLabelPart = part;
}
// Line from fault geometry to label
{
cvf::ref<cvf::Vec3fArray> vertices = new cvf::Vec3fArray;
vertices->reserve(2);
vertices->add(faultVertexToAttachLabel);
vertices->add(labelPosition);
cvf::ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;
geo->setVertexArray(vertices.p());
cvf::ref<cvf::PrimitiveSetDirect> primSet = new cvf::PrimitiveSetDirect(cvf::PT_LINES);
primSet->setStartIndex(0);
primSet->setIndexCount(vertices->size());
geo->addPrimitiveSet(primSet.p());
m_faultLabelLinePart = new cvf::Part;
m_faultLabelLinePart->setName("Anchor line for label" + cvf::String(static_cast<int>(m_grid->gridIndex())));
m_faultLabelLinePart->setDrawable(geo.p());
m_faultLabelLinePart->updateBoundingBox();
caf::MeshEffectGenerator gen(m_rimFault->faultColor());
cvf::ref<cvf::Effect> eff = gen.generateEffect();
m_faultLabelLinePart->setEffect(eff.p());
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Vec3f RivFaultPartMgr::findClosestVertex(const cvf::Vec3f& point, const cvf::Vec3fArray* vertices)
{
CVF_ASSERT(vertices);
if (!vertices) return cvf::Vec3f::UNDEFINED;
float closestDiff(HUGE_VAL);
size_t closestIndex = cvf::UNDEFINED_SIZE_T;
for (size_t i = 0; i < vertices->size(); i++)
{
float diff = point.pointDistance(vertices->get(i));
if (diff < closestDiff)
{
closestDiff = diff;
closestIndex = i;
}
}
if (closestIndex != cvf::UNDEFINED_SIZE_T)
{
return vertices->get(closestIndex);
}
else
{
return cvf::Vec3f::UNDEFINED;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultPartMgr::appendNativeFaultFacesToModel(cvf::ModelBasicList* model)
{
if (m_nativeFaultFaces.notNull())
{
model->addPart(m_nativeFaultFaces.p());
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultPartMgr::appendOppositeFaultFacesToModel(cvf::ModelBasicList* model)
{
if (m_oppositeFaultFaces.notNull())
{
model->addPart(m_oppositeFaultFaces.p());
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultPartMgr::appendLabelPartsToModel(cvf::ModelBasicList* model)
{
if (m_faultLabelPart.notNull()) model->addPart(m_faultLabelPart.p());
if (m_faultLabelLinePart.notNull()) model->addPart(m_faultLabelLinePart.p());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultPartMgr::appendMeshLinePartsToModel(cvf::ModelBasicList* model)
{
if (m_nativeFaultGridLines.notNull()) model->addPart(m_nativeFaultGridLines.p());
if (m_oppositeFaultGridLines.notNull()) model->addPart(m_oppositeFaultGridLines.p());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultPartMgr::appendNNCFacesToModel(cvf::ModelBasicList* model)
{
if (m_NNCFaces.notNull()) model->addPart(m_NNCFaces.p());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::Effect> RivFaultPartMgr::cellResultEffect(const cvf::ScalarMapper* mapper, caf::PolygonOffset polygonOffset) const
{
CVF_ASSERT(mapper);
caf::ScalarMapperEffectGenerator scalarEffgen(mapper, polygonOffset);
scalarEffgen.setFaceCulling(faceCullingMode());
scalarEffgen.setOpacityLevel(m_opacityLevel);
cvf::ref<cvf::Effect> scalarEffect = scalarEffgen.generateEffect();
return scalarEffect;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::FaceCulling RivFaultPartMgr::faceCullingMode() const
{
bool isShowingGrid = m_rimFaultCollection->isGridVisualizationMode();
if (!isShowingGrid )
{
if (m_rimFaultCollection->faultResult() == RimFaultCollection::FAULT_BACK_FACE_CULLING)
{
if (m_grid->mainGrid()->faceNormalsIsOutwards())
{
return caf::FC_BACK;
}
else
{
return caf::FC_FRONT;
}
}
else if (m_rimFaultCollection->faultResult() == RimFaultCollection::FAULT_FRONT_FACE_CULLING)
{
if (m_grid->mainGrid()->faceNormalsIsOutwards())
{
return caf::FC_FRONT;
}
else
{
return caf::FC_BACK;
}
}
else
{
return caf::FC_NONE;
}
}
else
{
// Do not perform face culling in grid mode to make sure the displayed grid is watertight
return caf::FC_NONE;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFaultPartMgr::updateNNCColors(RimResultSlot* cellResultSlot)
{
if (m_NNCFaces.isNull()) return;
if (cellResultSlot && cellResultSlot->resultVariable() == RimDefines::combinedTransmissibilityResultName())
{
const cvf::ScalarMapper* mapper = cellResultSlot->legendConfig()->scalarMapper();
m_NNCGenerator->textureCoordinates(m_NNCTextureCoords.p(), mapper);
cvf::ref<cvf::Effect> nncEffect;
if (m_rimFaultCollection->showFaultFaces || m_rimFaultCollection->showOppositeFaultFaces)
{
// Move NNC closer to camera to avoid z-fighting with grid surface
caf::ScalarMapperEffectGenerator nncEffgen(mapper, caf::PO_NEG_LARGE);
nncEffect = nncEffgen.generateEffect();
}
else
{
// If no grid is present, use same offset as grid geometry to be able to see mesh lines
caf::ScalarMapperEffectGenerator nncEffgen(mapper, caf::PO_1);
nncEffect = nncEffgen.generateEffect();
}
cvf::DrawableGeo* dg = dynamic_cast<cvf::DrawableGeo*>(m_NNCFaces->drawable());
if (dg) dg->setTextureCoordArray(m_NNCTextureCoords.p());
m_NNCFaces->setEffect(nncEffect.p());
}
else
{
// NNC faces a bit lighter than the fault for now
cvf::Color3f nncColor = m_defaultColor;
nncColor.r() += (1.0 - nncColor.r()) * 0.2;
nncColor.g() += (1.0 - nncColor.g()) * 0.2;
nncColor.g() += (1.0 - nncColor.b()) * 0.2;
cvf::ref<cvf::Effect> nncEffect;
if (m_rimFaultCollection->showFaultFaces || m_rimFaultCollection->showOppositeFaultFaces)
{
// Move NNC closer to camera to avoid z-fighting with grid surface
caf::SurfaceEffectGenerator nncEffgen(nncColor, caf::PO_NEG_LARGE);
nncEffect = nncEffgen.generateEffect();
}
else
{
// If no grid is present, use same offset as grid geometry to be able to see mesh lines
caf::SurfaceEffectGenerator nncEffgen(nncColor, caf::PO_1);
nncEffect = nncEffgen.generateEffect();
}
m_NNCFaces->setEffect(nncEffect.p());
}
}

View File

@@ -0,0 +1,107 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfBase.h"
#include "cvfObject.h"
#include "RigGridBase.h"
#include "RimFault.h"
#include "RivFaultGeometryGenerator.h"
#include "cvfColor4.h"
#include "RivNNCGeometryGenerator.h"
#include "cvfEffect.h"
#include "cafEffectGenerator.h"
namespace cvf
{
class StructGridInterface;
class ModelBasicList;
class Transform;
class Part;
}
class RimResultSlot;
class RimCellEdgeResultSlot;
class RimFaultCollection;
//==================================================================================================
///
///
//==================================================================================================
class RivFaultPartMgr : public cvf::Object
{
public:
RivFaultPartMgr(const RigGridBase* grid, const RimFaultCollection* rimFaultCollection, const RimFault* rimFault);
void setCellVisibility(cvf::UByteArray* cellVisibilities);
void applySingleColorEffect();
void updateCellResultColor(size_t timeStepIndex, RimResultSlot* cellResultSlot);
void updateCellEdgeResultColor(size_t timeStepIndex, RimResultSlot* cellResultSlot, RimCellEdgeResultSlot* cellEdgeResultSlot);
void appendNativeFaultFacesToModel(cvf::ModelBasicList* model);
void appendOppositeFaultFacesToModel(cvf::ModelBasicList* model);
void appendNNCFacesToModel(cvf::ModelBasicList* model);
void appendLabelPartsToModel(cvf::ModelBasicList* model);
void appendMeshLinePartsToModel(cvf::ModelBasicList* model);
private:
void generatePartGeometry();
void updatePartEffect();
void updateNNCColors(RimResultSlot* cellResultSlot);
cvf::ref<cvf::Effect> cellResultEffect(const cvf::ScalarMapper* mapper, caf::PolygonOffset polygonOffset) const;
caf::FaceCulling faceCullingMode() const;
void createLabelWithAnchorLine(const cvf::Part* part);
static cvf::Vec3f findClosestVertex(const cvf::Vec3f& point, const cvf::Vec3fArray* vertices);
private:
cvf::cref<RigGridBase> m_grid;
const RimFault* m_rimFault;
const RimFaultCollection* m_rimFaultCollection;
float m_opacityLevel;
cvf::Color3f m_defaultColor;
bool m_showNativeFaces;
bool m_showOppositeFaces;
bool m_showLabel;
cvf::ref<cvf::UByteArray> m_cellVisibility;
cvf::ref<RivFaultGeometryGenerator> m_nativeFaultGenerator;
cvf::ref<cvf::Part> m_nativeFaultFaces;
cvf::ref<cvf::Part> m_nativeFaultGridLines;
cvf::ref<cvf::Vec2fArray> m_nativeFaultFacesTextureCoords;
cvf::ref<RivFaultGeometryGenerator> m_oppositeFaultGenerator;
cvf::ref<cvf::Part> m_oppositeFaultFaces;
cvf::ref<cvf::Part> m_oppositeFaultGridLines;
cvf::ref<cvf::Vec2fArray> m_oppositeFaultFacesTextureCoords;
cvf::ref<RivNNCGeometryGenerator> m_NNCGenerator;
cvf::ref<cvf::Part> m_NNCFaces;
cvf::ref<cvf::Vec2fArray> m_NNCTextureCoords;
cvf::ref<cvf::Part> m_faultLabelPart;
cvf::ref<cvf::Part> m_faultLabelLinePart;
};

View File

@@ -40,6 +40,7 @@
#include "RimCellPropertyFilterCollection.h"
#include "Rim3dOverlayInfoConfig.h"
#include "RimReservoirCellResultsCacher.h"
#include "RivSourceInfo.h"
@@ -47,7 +48,7 @@
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivGridPartMgr::RivGridPartMgr(const RigGridBase* grid, size_t gridIdx)
RivGridPartMgr::RivGridPartMgr(const RigGridBase* grid, size_t gridIdx, const RimFaultCollection* rimFaultCollection)
: m_surfaceGenerator(grid),
m_faultGenerator(grid),
m_gridIdx(gridIdx),
@@ -55,7 +56,8 @@ RivGridPartMgr::RivGridPartMgr(const RigGridBase* grid, size_t gridIdx)
m_surfaceFaceFilter(grid),
m_faultFaceFilter(grid),
m_opacityLevel(1.0f),
m_defaultColor(cvf::Color3::WHITE)
m_defaultColor(cvf::Color3::WHITE),
m_rimFaultCollection(rimFaultCollection)
{
CVF_ASSERT(grid);
m_cellVisibility = new cvf::UByteArray;
@@ -82,13 +84,9 @@ void RivGridPartMgr::setCellVisibility(cvf::UByteArray* cellVisibilities)
m_cellVisibility = cellVisibilities;
m_surfaceGenerator.setCellVisibility(cellVisibilities);
m_surfaceFaceFilter.m_showExternalFaces = true;
m_surfaceFaceFilter.m_showFaultFaces = false;
m_surfaceGenerator.addFaceVisibilityFilter(&m_surfaceFaceFilter);
m_faultGenerator.setCellVisibility(cellVisibilities);
m_faultFaceFilter.m_showExternalFaces = false;
m_faultFaceFilter.m_showFaultFaces = true;
m_faultGenerator.addFaceVisibilityFilter(&m_faultFaceFilter);
generatePartGeometry(m_surfaceGenerator, false);
@@ -117,12 +115,15 @@ void RivGridPartMgr::generatePartGeometry(cvf::StructGridGeometryGenerator& geoB
part->setTransform(m_scaleTransform.p());
// Set mapping from triangle face index to cell index
part->setSourceInfo(geoBuilder.triangleToSourceGridCellMap().p());
cvf::ref<RivSourceInfo> si = new RivSourceInfo;
si->m_cellIndices = geoBuilder.triangleToSourceGridCellMap().p();
si->m_faceTypes = geoBuilder.triangleToFaceTypes().p();
part->setSourceInfo(si.p());
part->updateBoundingBox();
// Set default effect
caf::SurfaceEffectGenerator geometryEffgen(cvf::Color4f(cvf::Color3f::WHITE), true);
caf::SurfaceEffectGenerator geometryEffgen(cvf::Color4f(cvf::Color3f::WHITE), caf::PO_1);
cvf::ref<cvf::Effect> geometryOnlyEffect = geometryEffgen.generateEffect();
part->setEffect(geometryOnlyEffect.p());
@@ -192,8 +193,12 @@ void RivGridPartMgr::appendPartsToModel(cvf::ModelBasicList* model)
if(m_surfaceFaces.notNull() ) model->addPart(m_surfaceFaces.p() );
if(m_surfaceGridLines.notNull()) model->addPart(m_surfaceGridLines.p());
if(m_faultFaces.notNull() ) model->addPart(m_faultFaces.p() );
if(m_faultGridLines.notNull() ) model->addPart(m_faultGridLines.p() );
if (m_rimFaultCollection && m_rimFaultCollection->showGeometryDetectedFaults())
{
if(m_faultFaces.notNull() ) model->addPart(m_faultFaces.p() );
if(m_faultGridLines.notNull() ) model->addPart(m_faultGridLines.p() );
}
}
//--------------------------------------------------------------------------------------------------
@@ -204,7 +209,7 @@ void RivGridPartMgr::updateCellColor(cvf::Color4f color)
if (m_surfaceFaces.isNull() && m_faultFaces.isNull()) return;
// Set default effect
caf::SurfaceEffectGenerator geometryEffgen(color, true);
caf::SurfaceEffectGenerator geometryEffgen(color, caf::PO_1);
cvf::ref<cvf::Effect> geometryOnlyEffect = geometryEffgen.generateEffect();
if (m_surfaceFaces.notNull()) m_surfaceFaces->setEffect(geometryOnlyEffect.p());
@@ -245,25 +250,36 @@ void RivGridPartMgr::updateCellResultColor(size_t timeStepIndex, RimResultSlot*
{
CVF_ASSERT(cellResultSlot);
size_t scalarSetIndex = cellResultSlot->gridScalarIndex();
const cvf::ScalarMapper* mapper = cellResultSlot->legendConfig()->scalarMapper();
// If the result is static, only read that.
size_t resTimeStepIdx = timeStepIndex;
if (cellResultSlot->hasStaticResult()) resTimeStepIdx = 0;
RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultSlot->porosityModel());
RigCaseData* eclipseCase = cellResultSlot->reservoirView()->eclipseCase()->reservoirData();
cvf::ref<cvf::StructGridScalarDataAccess> dataAccessObject = eclipseCase->dataAccessObject(m_grid.p(), porosityModel, resTimeStepIdx, scalarSetIndex);
if (dataAccessObject.isNull()) return;
// Outer surface
if (m_surfaceFaces.notNull())
{
m_surfaceGenerator.textureCoordinates(m_surfaceFacesTextureCoords.p(), dataAccessObject.p(), mapper);
if (cellResultSlot->resultVariable().compare(RimDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0)
{
const std::vector<cvf::StructGridInterface::FaceType>& quadsToFaceTypes = m_surfaceGenerator.quadToFace();
const std::vector<size_t>& quadsToGridCells = m_surfaceGenerator.quadToGridCellIndices();
cvf::Vec2fArray* textureCoords = m_surfaceFacesTextureCoords.p();
RivTransmissibilityColorMapper::updateCombinedTransmissibilityTextureCoordinates(cellResultSlot, m_grid.p(), textureCoords, quadsToFaceTypes, quadsToGridCells);
}
else
{
size_t scalarSetIndex = cellResultSlot->gridScalarIndex();
// If the result is static, only read that.
size_t resTimeStepIdx = timeStepIndex;
if (cellResultSlot->hasStaticResult()) resTimeStepIdx = 0;
RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultSlot->porosityModel());
cvf::ref<cvf::StructGridScalarDataAccess> dataAccessObject = eclipseCase->dataAccessObject(m_grid.p(), porosityModel, resTimeStepIdx, scalarSetIndex);
if (dataAccessObject.isNull()) return;
m_surfaceGenerator.textureCoordinates(m_surfaceFacesTextureCoords.p(), dataAccessObject.p(), mapper);
}
// if this gridpart manager is set to have some transparency, we
// interpret it as we are displaying beeing wellcells. The cells are then transparent by default, but
@@ -295,8 +311,8 @@ void RivGridPartMgr::updateCellResultColor(size_t timeStepIndex, RimResultSlot*
cvf::DrawableGeo* dg = dynamic_cast<cvf::DrawableGeo*>(m_surfaceFaces->drawable());
if (dg) dg->setTextureCoordArray(m_surfaceFacesTextureCoords.p());
bool usePolygonOffset = true;
caf::ScalarMapperEffectGenerator scalarEffgen(mapper, usePolygonOffset);
caf::PolygonOffset polygonOffset = caf::PO_1;
caf::ScalarMapperEffectGenerator scalarEffgen(mapper, polygonOffset);
scalarEffgen.setOpacityLevel(m_opacityLevel);
@@ -308,6 +324,16 @@ void RivGridPartMgr::updateCellResultColor(size_t timeStepIndex, RimResultSlot*
// Faults
if (m_faultFaces.notNull())
{
size_t scalarSetIndex = cellResultSlot->gridScalarIndex();
// If the result is static, only read that.
size_t resTimeStepIdx = timeStepIndex;
if (cellResultSlot->hasStaticResult()) resTimeStepIdx = 0;
RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultSlot->porosityModel());
cvf::ref<cvf::StructGridScalarDataAccess> dataAccessObject = eclipseCase->dataAccessObject(m_grid.p(), porosityModel, resTimeStepIdx, scalarSetIndex);
if (dataAccessObject.isNull()) return;
m_faultGenerator.textureCoordinates(m_faultFacesTextureCoords.p(), dataAccessObject.p(), mapper);
if (m_opacityLevel < 1.0f )
@@ -336,8 +362,8 @@ void RivGridPartMgr::updateCellResultColor(size_t timeStepIndex, RimResultSlot*
cvf::DrawableGeo* dg = dynamic_cast<cvf::DrawableGeo*>(m_faultFaces->drawable());
if (dg) dg->setTextureCoordArray(m_faultFacesTextureCoords.p());
bool usePolygonOffset = true;
caf::ScalarMapperEffectGenerator scalarEffgen(mapper, usePolygonOffset);
caf::PolygonOffset polygonOffset = caf::PO_1;
caf::ScalarMapperEffectGenerator scalarEffgen(mapper, polygonOffset);
scalarEffgen.setOpacityLevel(m_opacityLevel);
@@ -406,3 +432,106 @@ RivGridPartMgr::~RivGridPartMgr()
if (m_surfaceFaces.notNull()) m_surfaceFaces->deleteOrReleaseOpenGLResources();
#endif
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivTransmissibilityColorMapper::updateCombinedTransmissibilityTextureCoordinates(RimResultSlot* cellResultSlot,
const RigGridBase* grid,
cvf::Vec2fArray* textureCoords,
const std::vector<cvf::StructGridInterface::FaceType>& quadsToFaceTypes,
const std::vector<size_t>& quadsToGridCells)
{
const cvf::ScalarMapper* mapper = cellResultSlot->legendConfig()->scalarMapper();
if (!mapper) return;
const RimReservoirCellResultsStorage* gridCellResults = cellResultSlot->currentGridCellResults();
if (!gridCellResults) return;
RigCaseData* eclipseCase = cellResultSlot->reservoirView()->eclipseCase()->reservoirData();
if (!eclipseCase) return;
size_t tranPosXScalarSetIndex, tranPosYScalarSetIndex, tranPosZScalarSetIndex;
if (!gridCellResults->cellResults()->findTransmissibilityResults(tranPosXScalarSetIndex, tranPosYScalarSetIndex, tranPosZScalarSetIndex)) return;
// If the result is static, only read that.
size_t resTimeStepIdx = 0;
RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultSlot->porosityModel());
cvf::ref<cvf::StructGridScalarDataAccess> dataAccessObjectTranX = eclipseCase->dataAccessObject(grid, porosityModel, resTimeStepIdx, tranPosXScalarSetIndex);
cvf::ref<cvf::StructGridScalarDataAccess> dataAccessObjectTranY = eclipseCase->dataAccessObject(grid, porosityModel, resTimeStepIdx, tranPosYScalarSetIndex);
cvf::ref<cvf::StructGridScalarDataAccess> dataAccessObjectTranZ = eclipseCase->dataAccessObject(grid, porosityModel, resTimeStepIdx, tranPosZScalarSetIndex);
size_t numVertices = quadsToGridCells.size()*4;
textureCoords->resize(numVertices);
cvf::Vec2f* rawPtr = textureCoords->ptr();
double cellScalarValue;
cvf::Vec2f texCoord;
#pragma omp parallel for private(texCoord, cellScalarValue)
for (int idx = 0; idx < static_cast<int>(quadsToGridCells.size()); idx++)
{
cellScalarValue = HUGE_VAL;
if (quadsToFaceTypes[idx] == cvf::StructGridInterface::POS_I)
{
cellScalarValue = dataAccessObjectTranX->cellScalar(quadsToGridCells[idx]);
}
else if (quadsToFaceTypes[idx] == cvf::StructGridInterface::NEG_I)
{
size_t i, j, k, neighborGridCellIdx;
grid->ijkFromCellIndex(quadsToGridCells[idx], &i, &j, &k);
if(grid->cellIJKNeighbor(i, j, k, cvf::StructGridInterface::POS_I, &neighborGridCellIdx))
{
cellScalarValue = dataAccessObjectTranX->cellScalar(neighborGridCellIdx);
}
}
else if (quadsToFaceTypes[idx] == cvf::StructGridInterface::POS_J)
{
cellScalarValue = dataAccessObjectTranY->cellScalar(quadsToGridCells[idx]);
}
else if (quadsToFaceTypes[idx] == cvf::StructGridInterface::NEG_J)
{
size_t i, j, k, neighborGridCellIdx;
grid->ijkFromCellIndex(quadsToGridCells[idx], &i, &j, &k);
if(grid->cellIJKNeighbor(i, j, k, cvf::StructGridInterface::POS_J, &neighborGridCellIdx))
{
cellScalarValue = dataAccessObjectTranY->cellScalar(neighborGridCellIdx);
}
}
else if (quadsToFaceTypes[idx] == cvf::StructGridInterface::POS_K)
{
cellScalarValue = dataAccessObjectTranZ->cellScalar(quadsToGridCells[idx]);
}
else if (quadsToFaceTypes[idx] == cvf::StructGridInterface::NEG_K)
{
size_t i, j, k, neighborGridCellIdx;
grid->ijkFromCellIndex(quadsToGridCells[idx], &i, &j, &k);
if(grid->cellIJKNeighbor(i, j, k, cvf::StructGridInterface::POS_K, &neighborGridCellIdx))
{
cellScalarValue = dataAccessObjectTranZ->cellScalar(neighborGridCellIdx);
}
}
texCoord = mapper->mapToTextureCoord(cellScalarValue);
if (cellScalarValue == HUGE_VAL || cellScalarValue != cellScalarValue) // a != a is true for NAN's
{
texCoord[1] = 1.0f;
}
size_t j;
for (j = 0; j < 4; j++)
{
rawPtr[idx*4 + j] = texCoord;
}
}
}

View File

@@ -33,6 +33,26 @@ namespace cvf
class RimResultSlot;
class RimCellEdgeResultSlot;
class RimFaultCollection;
//==================================================================================================
///
///
//==================================================================================================
class RivTransmissibilityColorMapper
{
public:
static void updateCombinedTransmissibilityTextureCoordinates(
RimResultSlot* cellResultSlot,
const RigGridBase* grid,
cvf::Vec2fArray* textureCoords,
const std::vector<cvf::StructGridInterface::FaceType>& quadsToFaceTypes,
const std::vector<size_t>& quadsToGridCells);
};
//==================================================================================================
///
@@ -45,7 +65,7 @@ class RimCellEdgeResultSlot;
class RivGridPartMgr: public cvf::Object
{
public:
RivGridPartMgr(const RigGridBase* grid, size_t gridIdx);
RivGridPartMgr(const RigGridBase* grid, size_t gridIdx, const RimFaultCollection* rimFaultCollection);
~RivGridPartMgr();
void setTransform(cvf::Transform* scaleTransform);
void setCellVisibility(cvf::UByteArray* cellVisibilities );
@@ -58,16 +78,10 @@ public:
void appendPartsToModel(cvf::ModelBasicList* model);
enum PartRenderMaskEnum
{
surfaceBit = 0x00000001,
meshSurfaceBit = 0x00000002,
faultBit = 0x00000004,
meshFaultBit = 0x00000008,
};
private:
void generatePartGeometry(cvf::StructGridGeometryGenerator& geoBuilder, bool faultGeometry);
private:
size_t m_gridIdx;
@@ -87,13 +101,13 @@ private:
// Fault visualization
cvf::StructGridGeometryGenerator m_faultGenerator;
RigGridCellFaceVisibilityFilter m_faultFaceFilter;
RigFaultFaceVisibilityFilter m_faultFaceFilter;
cvf::ref<cvf::Part> m_faultFaces;
cvf::ref<cvf::Vec2fArray> m_faultFacesTextureCoords;
cvf::ref<cvf::Part> m_faultGridLines;
cvf::ref<cvf::UByteArray> m_cellVisibility;
cvf::ref<cvf::UByteArray> m_cellVisibility;
//cvf::ref<cvf::Part> m_gridOutlines;
const RimFaultCollection* m_rimFaultCollection;
};

View File

@@ -0,0 +1,191 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RivNNCGeometryGenerator.h"
#include <cmath>
#include "cvfDrawableGeo.h"
#include "cvfPrimitiveSetIndexedUInt.h"
#include "cvfScalarMapper.h"
#include "RigNNCData.h"
#include "RigCell.h"
#include "RigMainGrid.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivNNCGeometryGenerator::RivNNCGeometryGenerator(const RigNNCData* nncData, const cvf::Vec3d& offset, const cvf::Array<size_t>* nncIndexes )
: m_nncData(nncData),
m_nncIndexes(nncIndexes),
m_offset(offset)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivNNCGeometryGenerator::~RivNNCGeometryGenerator()
{
}
//--------------------------------------------------------------------------------------------------
/// Generate surface drawable geo from the specified region
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableGeo> RivNNCGeometryGenerator::generateSurface()
{
computeArrays();
CVF_ASSERT(m_vertices.notNull());
if (m_vertices->size() == 0) return NULL;
cvf::ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;
geo->setFromTriangleVertexArray(m_vertices.p());
return geo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivNNCGeometryGenerator::computeArrays()
{
std::vector<cvf::Vec3f> vertices;
std::vector<size_t> triangleToNNC;
const cvf::Vec3d offset = m_offset;
long long numConnections = static_cast<long long>(m_nncIndexes.isNull()? m_nncData->connections().size(): m_nncIndexes->size());
bool isVisibilityCalcActive = m_cellVisibility.notNull() && m_grid.notNull();
std::vector<RigCell>* allCells = NULL;
if (isVisibilityCalcActive)
{
allCells = &(m_grid->mainGrid()->cells());
}
#pragma omp parallel for ordered
for (long long nIdx = 0; nIdx < numConnections; ++nIdx)
{
size_t conIdx = m_nncIndexes.isNull()? nIdx: (*m_nncIndexes)[nIdx];
const RigConnection& conn = m_nncData->connections()[conIdx];
if (conn.m_polygon.size())
{
bool isVisible = true;
if (isVisibilityCalcActive)
{
bool cell1Visible = false;
bool cell2Visible = false;
if ((*allCells)[conn.m_c1GlobIdx].hostGrid() == m_grid.p())
{
size_t cell1GridLocalIdx = (*allCells)[conn.m_c1GlobIdx].cellIndex();
cell1Visible = (*m_cellVisibility)[cell1GridLocalIdx];
}
if ((*allCells)[conn.m_c2GlobIdx].hostGrid() == m_grid.p())
{
size_t cell2GridLocalIdx = (*allCells)[conn.m_c2GlobIdx].cellIndex();
cell2Visible = (*m_cellVisibility)[cell2GridLocalIdx];
}
isVisible = cell1Visible || cell2Visible;
}
if (isVisible)
{
cvf::Vec3f vx1 = cvf::Vec3f(conn.m_polygon[0] - offset);
cvf::Vec3f vx2;
cvf::Vec3f vx3 = cvf::Vec3f(conn.m_polygon[1] - offset);
for (size_t vxIdx = 2; vxIdx < conn.m_polygon.size() ; ++vxIdx)
{
vx2 = vx3;
vx3 = cvf::Vec3f( conn.m_polygon[vxIdx] - offset);
#pragma omp critical
{
vertices.push_back(vx1);
vertices.push_back(vx2);
vertices.push_back(vx3);
triangleToNNC.push_back(conIdx);
}
}
}
}
}
m_vertices = new cvf::Vec3fArray;
m_vertices->assign(vertices);
m_triangleIndexToNNCIndex = new cvf::Array<size_t>;
m_triangleIndexToNNCIndex->assign(triangleToNNC);
}
//--------------------------------------------------------------------------------------------------
/// Calculates the texture coordinates in a "nearly" one dimensional texture.
/// Undefined values are coded with a y-texture coordinate value of 1.0 instead of the normal 0.5
//--------------------------------------------------------------------------------------------------
void RivNNCGeometryGenerator::textureCoordinates(cvf::Vec2fArray* textureCoords, const cvf::ScalarMapper* mapper) const
{
size_t numVertices = m_vertices->size();
textureCoords->resize(numVertices);
cvf::Vec2f* rawPtr = textureCoords->ptr();
double cellScalarValue;
cvf::Vec2f texCoord;
#pragma omp parallel for private(texCoord, cellScalarValue)
for (int tIdx = 0; tIdx < static_cast<int>(m_triangleIndexToNNCIndex->size()); tIdx++)
{
cellScalarValue = m_nncData->connections()[(*m_triangleIndexToNNCIndex)[tIdx]].m_transmissibility;
texCoord = mapper->mapToTextureCoord(cellScalarValue);
if (cellScalarValue == HUGE_VAL || cellScalarValue != cellScalarValue) // a != a is true for NAN's
{
texCoord[1] = 1.0f;
}
size_t j;
for (j = 0; j < 3; j++)
{
rawPtr[tIdx*3 + j] = texCoord;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivNNCGeometryGenerator::setCellVisibility(const cvf::UByteArray* cellVisibility, const RigGridBase * grid)
{
m_cellVisibility = cellVisibility;
m_grid = grid;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::Array<size_t> > RivNNCGeometryGenerator::triangleToNNCIndex() const
{
return m_triangleIndexToNNCIndex;
}

View File

@@ -0,0 +1,70 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfBase.h"
#include "cvfObject.h"
#include "cvfArray.h"
namespace cvf
{
class ScalarMapper;
class DrawableGeo;
}
class RigNNCData;
class RigGridBase;
//==================================================================================================
///
///
//==================================================================================================
class RivNNCGeometryGenerator : public cvf::Object
{
public:
RivNNCGeometryGenerator(const RigNNCData* nncData, const cvf::Vec3d& offset, const cvf::Array<size_t>* nncIndexes );
~RivNNCGeometryGenerator();
void setCellVisibility( const cvf::UByteArray* cellVisibilities, const RigGridBase * grid);
void textureCoordinates(cvf::Vec2fArray* textureCoords,
const cvf::ScalarMapper* mapper) const;
// Mapping between cells and geometry
cvf::ref<cvf::Array<size_t> > triangleToNNCIndex() const;
// Generated geometry
cvf::ref<cvf::DrawableGeo> generateSurface();
private:
void computeArrays();
private:
// Input
cvf::cref<RigNNCData> m_nncData;
cvf::cref<cvf::Array<size_t> > m_nncIndexes;
cvf::cref<cvf::UByteArray> m_cellVisibility;
cvf::cref<RigGridBase> m_grid;
cvf::Vec3d m_offset;
// Triangles
cvf::ref<cvf::Vec3fArray> m_vertices;
// Mappings
cvf::ref<cvf::Array<size_t> > m_triangleIndexToNNCIndex;
};

View File

@@ -0,0 +1,235 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RivReservoirFaultsPartMgr.h"
#include "cvfPart.h"
#include "cvfModelBasicList.h"
#include "cvfColor3.h"
#include "cvfTransform.h"
#include "cafPdmFieldCvfColor.h"
#include "RimFaultCollection.h"
#include "RigMainGrid.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivReservoirFaultsPartMgr::RivReservoirFaultsPartMgr(const RigMainGrid* grid, const RimFaultCollection* faultCollection)
: m_faultCollection(faultCollection)
{
CVF_ASSERT(grid);
if (faultCollection)
{
for (size_t i = 0; i < faultCollection->faults.size(); i++)
{
m_faultParts.push_back(new RivFaultPartMgr(grid, faultCollection, faultCollection->faults[i]));
}
}
m_forceVisibility = false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivReservoirFaultsPartMgr::~RivReservoirFaultsPartMgr()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirFaultsPartMgr::setTransform(cvf::Transform* scaleTransform)
{
m_scaleTransform = scaleTransform;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirFaultsPartMgr::setCellVisibility(cvf::UByteArray* cellVisibilities)
{
CVF_ASSERT(cellVisibilities);
for (size_t i = 0; i < m_faultParts.size(); i++)
{
m_faultParts.at(i)->setCellVisibility(cellVisibilities);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirFaultsPartMgr::appendPartsToModel(cvf::ModelBasicList* model)
{
CVF_ASSERT(model != NULL);
if (!m_faultCollection) return;
bool isShowingGrid = m_faultCollection->isGridVisualizationMode();
if (!m_faultCollection->showFaultCollection() && !isShowingGrid) return;
// Check match between model fault count and fault parts
CVF_ASSERT(m_faultCollection->faults.size() == m_faultParts.size());
cvf::ModelBasicList parts;
for (size_t i = 0; i < m_faultCollection->faults.size(); i++)
{
const RimFault* rimFault = m_faultCollection->faults[i];
cvf::ref<RivFaultPartMgr> rivFaultPart = m_faultParts[i];
CVF_ASSERT(rivFaultPart.notNull());
// Parts that is overridden by the grid settings
bool forceDisplayOfFault = isShowingGrid;
if (m_forceVisibility)
{
forceDisplayOfFault = true;
}
if (rimFault->showFault() || forceDisplayOfFault)
{
if (m_faultCollection->showFaultFaces() || forceDisplayOfFault)
{
rivFaultPart->appendNativeFaultFacesToModel(&parts);
}
if (m_faultCollection->showOppositeFaultFaces() || forceDisplayOfFault)
{
rivFaultPart->appendOppositeFaultFacesToModel(&parts);
}
if (m_faultCollection->showFaultFaces() || m_faultCollection->showOppositeFaultFaces() || m_faultCollection->showNNCs() || forceDisplayOfFault)
{
rivFaultPart->appendMeshLinePartsToModel(&parts);
}
}
// Parts that is not overridden by the grid settings
if (rimFault->showFault() && m_faultCollection->showFaultCollection())
{
if (m_faultCollection->showNNCs())
{
rivFaultPart->appendNNCFacesToModel(&parts);
}
}
}
for (size_t i = 0; i < parts.partCount(); i++)
{
cvf::Part* part = parts.part(i);
part->setTransform(m_scaleTransform.p());
model->addPart(part);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirFaultsPartMgr::applySingleColorEffect()
{
for (size_t i = 0; i < m_faultParts.size(); i++)
{
m_faultParts[i]->applySingleColorEffect();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirFaultsPartMgr::updateColors(size_t timeStepIndex, RimResultSlot* cellResultSlot)
{
if (m_faultCollection->showResultsOnFaults())
{
for (size_t i = 0; i < m_faultParts.size(); i++)
{
m_faultParts[i]->updateCellResultColor(timeStepIndex, cellResultSlot);
}
}
else
{
applySingleColorEffect();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirFaultsPartMgr::updateCellEdgeResultColor(size_t timeStepIndex, RimResultSlot* cellResultSlot, RimCellEdgeResultSlot* cellEdgeResultSlot)
{
for (size_t i = 0; i < m_faultParts.size(); i++)
{
m_faultParts[i]->updateCellEdgeResultColor(timeStepIndex, cellResultSlot, cellEdgeResultSlot);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirFaultsPartMgr::appendLabelPartsToModel(cvf::ModelBasicList* model)
{
CVF_ASSERT(model != NULL);
if (!m_faultCollection) return;
if (!m_faultCollection->showFaultCollection()) return;
if (!m_faultCollection->showFaultLabel() ) return;
// Check match between model fault count and fault parts
CVF_ASSERT(m_faultCollection->faults.size() == m_faultParts.size());
cvf::ModelBasicList parts;
for (size_t i = 0; i < m_faultCollection->faults.size(); i++)
{
const RimFault* rimFault = m_faultCollection->faults[i];
cvf::ref<RivFaultPartMgr> rivFaultPart = m_faultParts[i];
CVF_ASSERT(rivFaultPart.notNull());
if (rimFault->showFault())
{
rivFaultPart->appendLabelPartsToModel(&parts);
}
}
for (size_t i = 0; i < parts.partCount(); i++)
{
cvf::Part* part = parts.part(i);
part->setTransform(m_scaleTransform.p());
model->addPart(part);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirFaultsPartMgr::setFaultForceVisibility(bool forceVisibility)
{
m_forceVisibility = forceVisibility;
}

View File

@@ -0,0 +1,64 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfBase.h"
#include "cvfObject.h"
#include "RigGridBase.h"
#include "RivFaultPartMgr.h"
namespace cvf
{
class Transform;
}
class RimResultSlot;
class RimCellEdgeResultSlot;
class RimFaultCollection;
//==================================================================================================
///
//==================================================================================================
class RivReservoirFaultsPartMgr : public cvf::Object
{
public:
RivReservoirFaultsPartMgr(const RigMainGrid* grid, const RimFaultCollection* faultCollection);
~RivReservoirFaultsPartMgr();
void setTransform(cvf::Transform* scaleTransform);
void setCellVisibility(cvf::UByteArray* cellVisibilities);
void setFaultForceVisibility(bool isFilterGenerated);
void applySingleColorEffect();
void updateColors(size_t timeStepIndex, RimResultSlot* cellResultSlot);
void updateCellEdgeResultColor(size_t timeStepIndex, RimResultSlot* cellResultSlot,
RimCellEdgeResultSlot* cellEdgeResultSlot);
void appendPartsToModel(cvf::ModelBasicList* model);
void appendLabelPartsToModel(cvf::ModelBasicList* model);
private:
cvf::ref<cvf::Transform> m_scaleTransform;
const RimFaultCollection* m_faultCollection;
cvf::Collection<RivFaultPartMgr> m_faultParts;
bool m_forceVisibility;
};

View File

@@ -18,25 +18,31 @@
#include "RiaStdInclude.h"
#include "RivReservoirPartMgr.h"
#include "RivGridPartMgr.h"
#include "cvfStructGrid.h"
#include "cvfModelBasicList.h"
#include "RigCaseData.h"
#include "RivGridPartMgr.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirPartMgr::clearAndSetReservoir(const RigCaseData* eclipseCase)
void RivReservoirPartMgr::clearAndSetReservoir(const RigCaseData* eclipseCase, const RimFaultCollection* faultCollection)
{
m_allGrids.clear();
if (eclipseCase)
{
std::vector<const RigGridBase*> grids;
eclipseCase->allGrids(&grids);
for (size_t i = 0; i < grids.size() ; ++i)
{
m_allGrids.push_back(new RivGridPartMgr(grids[i], i) );
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);
}
}
@@ -49,6 +55,11 @@ void RivReservoirPartMgr::setTransform(cvf::Transform* scaleTransform)
{
m_allGrids[i]->setTransform(scaleTransform);
}
if (m_faultsPartMgr.notNull())
{
m_faultsPartMgr->setTransform(scaleTransform);
}
}
//--------------------------------------------------------------------------------------------------
@@ -58,6 +69,12 @@ void RivReservoirPartMgr::setCellVisibility(size_t gridIndex, cvf::UByteArray* c
{
CVF_ASSERT(gridIndex < m_allGrids.size());
m_allGrids[gridIndex]->setCellVisibility(cellVisibilities);
if (gridIndex == 0)
{
CVF_ASSERT(m_faultsPartMgr.notNull());
m_faultsPartMgr->setCellVisibility(cellVisibilities);
}
}
//--------------------------------------------------------------------------------------------------
@@ -78,6 +95,11 @@ void RivReservoirPartMgr::updateCellColor(cvf::Color4f color)
{
m_allGrids[i]->updateCellColor(color);
}
if (m_faultsPartMgr.notNull())
{
m_faultsPartMgr->applySingleColorEffect();
}
}
//--------------------------------------------------------------------------------------------------
@@ -105,7 +127,7 @@ void RivReservoirPartMgr::updateCellEdgeResultColor(size_t timeStepIndex, RimRes
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirPartMgr::appendPartsToModel(cvf::ModelBasicList* model)
void RivReservoirPartMgr::appendGridPartsToModel(cvf::ModelBasicList* model)
{
for (size_t i = 0; i < m_allGrids.size() ; ++i)
{
@@ -116,7 +138,7 @@ void RivReservoirPartMgr::appendPartsToModel(cvf::ModelBasicList* model)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirPartMgr::appendPartsToModel(cvf::ModelBasicList* model, const std::vector<size_t>& gridIndices)
void RivReservoirPartMgr::appendGridPartsToModel(cvf::ModelBasicList* model, const std::vector<size_t>& gridIndices)
{
for (size_t i = 0; i < gridIndices.size() ; ++i)
{
@@ -126,3 +148,48 @@ void RivReservoirPartMgr::appendPartsToModel(cvf::ModelBasicList* model, const s
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirPartMgr::updateFaultColors(size_t timeStepIndex, RimResultSlot* cellResultSlot)
{
if (m_faultsPartMgr.notNull())
{
m_faultsPartMgr->updateColors(timeStepIndex, cellResultSlot);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirPartMgr::appendFaultPartsToModel(cvf::ModelBasicList* model)
{
if (m_faultsPartMgr.notNull())
{
m_faultsPartMgr->appendPartsToModel(model);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirPartMgr::appendFaultLabelPartsToModel(cvf::ModelBasicList* model)
{
if (m_faultsPartMgr.notNull())
{
m_faultsPartMgr->appendLabelPartsToModel(model);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirPartMgr::setFaultForceVisibility(bool isGeneratedByFilter)
{
if (m_faultsPartMgr.notNull())
{
m_faultsPartMgr->setFaultForceVisibility(isGeneratedByFilter);
}
}

View File

@@ -21,6 +21,8 @@
#include "cvfArray.h"
#include "cvfCollection.h"
#include "RivReservoirFaultsPartMgr.h"
namespace cvf
{
class ModelBasicList;
@@ -31,7 +33,7 @@ class RimResultSlot;
class RimCellEdgeResultSlot;
class RivGridPartMgr;
class RigCaseData;
class RimFaultCollection;
//==================================================================================================
///
@@ -43,9 +45,10 @@ class RigCaseData;
class RivReservoirPartMgr: public cvf::Object
{
public:
void clearAndSetReservoir(const RigCaseData* eclipseCase);
void clearAndSetReservoir(const RigCaseData* eclipseCase, const RimFaultCollection* faultCollection);
void setTransform(cvf::Transform* scaleTransform);
void setCellVisibility(size_t gridIndex, cvf::UByteArray* cellVisibilities );
void setFaultForceVisibility(bool isGeneratedByFilter);
//size_t gridCount() { return m_allGrids.size(); }
cvf::ref<cvf::UByteArray>
@@ -56,10 +59,15 @@ public:
void updateCellEdgeResultColor(size_t timeStepIndex, RimResultSlot* cellResultSlot,
RimCellEdgeResultSlot* cellEdgeResultSlot);
void appendPartsToModel(cvf::ModelBasicList* model, const std::vector<size_t>& gridIdxes);
void appendPartsToModel(cvf::ModelBasicList* model);
void appendGridPartsToModel(cvf::ModelBasicList* model, const std::vector<size_t>& gridIdxes);
void appendGridPartsToModel(cvf::ModelBasicList* model);
// Faults
void updateFaultColors(size_t timeStepIndex, RimResultSlot* cellResultSlot);
void appendFaultPartsToModel(cvf::ModelBasicList* model);
void appendFaultLabelPartsToModel(cvf::ModelBasicList* model);
private:
cvf::Collection<RivGridPartMgr> m_allGrids; // Main grid and all LGR's
cvf::Collection<RivGridPartMgr> m_allGrids; // Main grid and all LGR's
cvf::ref<RivReservoirFaultsPartMgr> m_faultsPartMgr;
};

View File

@@ -151,7 +151,7 @@ void RivReservoirViewPartMgr::clearGeometryCache(ReservoirGeometryCacheType geom
m_propFilteredGeometryFramesNeedsRegen[i] = true;
if (m_propFilteredGeometryFrames[i].notNull())
{
m_propFilteredGeometryFrames[i]->clearAndSetReservoir(eclipseCase);
m_propFilteredGeometryFrames[i]->clearAndSetReservoir(eclipseCase, m_reservoirView->faultCollection());
m_propFilteredGeometryFrames[i]->setTransform(m_scaleTransform.p());
}
}
@@ -163,7 +163,7 @@ void RivReservoirViewPartMgr::clearGeometryCache(ReservoirGeometryCacheType geom
m_propFilteredWellGeometryFramesNeedsRegen[i] = true;
if (m_propFilteredWellGeometryFrames[i].notNull())
{
m_propFilteredWellGeometryFrames[i]->clearAndSetReservoir(eclipseCase);
m_propFilteredWellGeometryFrames[i]->clearAndSetReservoir(eclipseCase, m_reservoirView->faultCollection());
m_propFilteredWellGeometryFrames[i]->setTransform(m_scaleTransform.p());
}
}
@@ -171,7 +171,7 @@ void RivReservoirViewPartMgr::clearGeometryCache(ReservoirGeometryCacheType geom
else
{
m_geometriesNeedsRegen[geomType] = true;
m_geometries[geomType].clearAndSetReservoir(eclipseCase);
m_geometries[geomType].clearAndSetReservoir(eclipseCase, m_reservoirView->faultCollection());
m_geometries[geomType].setTransform(m_scaleTransform.p());
}
}
@@ -205,7 +205,7 @@ void RivReservoirViewPartMgr::appendStaticGeometryPartsToModel(cvf::ModelBasicLi
{
createGeometry( geometryType);
}
m_geometries[geometryType].appendPartsToModel(model, gridIndices);
m_geometries[geometryType].appendGridPartsToModel(model, gridIndices);
}
//--------------------------------------------------------------------------------------------------
@@ -220,7 +220,7 @@ void RivReservoirViewPartMgr::appendDynamicGeometryPartsToModel(cvf::ModelBasicL
{
createPropertyFilteredNoneWellCellGeometry(frameIndex);
}
m_propFilteredGeometryFrames[frameIndex]->appendPartsToModel(model, gridIndices);
m_propFilteredGeometryFrames[frameIndex]->appendGridPartsToModel(model, gridIndices);
}
else if (geometryType == PROPERTY_FILTERED_WELL_CELLS)
{
@@ -228,7 +228,7 @@ void RivReservoirViewPartMgr::appendDynamicGeometryPartsToModel(cvf::ModelBasicL
{
createPropertyFilteredWellGeometry(frameIndex);
}
m_propFilteredWellGeometryFrames[frameIndex]->appendPartsToModel(model, gridIndices);
m_propFilteredWellGeometryFrames[frameIndex]->appendGridPartsToModel(model, gridIndices);
}
}
@@ -238,8 +238,9 @@ void RivReservoirViewPartMgr::appendDynamicGeometryPartsToModel(cvf::ModelBasicL
void RivReservoirViewPartMgr::createGeometry(ReservoirGeometryCacheType geometryType)
{
RigCaseData* res = m_reservoirView->eclipseCase()->reservoirData();
m_geometries[geometryType].clearAndSetReservoir(res);
m_geometries[geometryType].clearAndSetReservoir(res, m_reservoirView->faultCollection());
m_geometries[geometryType].setTransform(m_scaleTransform.p());
std::vector<RigGridBase*> grids;
res->allGrids(&grids);
@@ -393,7 +394,7 @@ void RivReservoirViewPartMgr::createPropertyFilteredNoneWellCellGeometry(size_t
if ( m_propFilteredGeometryFrames[frameIndex].isNull()) m_propFilteredGeometryFrames[frameIndex] = new RivReservoirPartMgr;
m_propFilteredGeometryFrames[frameIndex]->clearAndSetReservoir(res);
m_propFilteredGeometryFrames[frameIndex]->clearAndSetReservoir(res, m_reservoirView->faultCollection());
m_propFilteredGeometryFrames[frameIndex]->setTransform(m_scaleTransform.p());
std::vector<RigGridBase*> grids;
@@ -470,7 +471,7 @@ void RivReservoirViewPartMgr::createPropertyFilteredWellGeometry(size_t frameInd
if ( m_propFilteredWellGeometryFrames[frameIndex].isNull()) m_propFilteredWellGeometryFrames[frameIndex] = new RivReservoirPartMgr;
m_propFilteredWellGeometryFrames[frameIndex]->clearAndSetReservoir(res);
m_propFilteredWellGeometryFrames[frameIndex]->clearAndSetReservoir(res, m_reservoirView->faultCollection());
m_propFilteredWellGeometryFrames[frameIndex]->setTransform(m_scaleTransform.p());
std::vector<RigGridBase*> grids;
@@ -818,3 +819,105 @@ RivReservoirPartMgr * RivReservoirViewPartMgr::reservoirPartManager(ReservoirGeo
return &m_geometries[geometryType];
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirViewPartMgr::updateFaultColors(ReservoirGeometryCacheType geometryType, size_t timeStepIndex, RimResultSlot* cellResultSlot)
{
if (geometryType == PROPERTY_FILTERED && timeStepIndex >= m_propFilteredGeometryFrames.size())
{
return;
}
if (geometryType == PROPERTY_FILTERED_WELL_CELLS && timeStepIndex >= m_propFilteredWellGeometryFrames.size())
{
return;
}
RivReservoirPartMgr* pmgr = reservoirPartManager(geometryType, timeStepIndex);
pmgr->updateFaultColors(timeStepIndex, cellResultSlot);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirViewPartMgr::appendFaultsStaticGeometryPartsToModel(cvf::ModelBasicList* model, ReservoirGeometryCacheType geometryType)
{
if (m_geometriesNeedsRegen[geometryType])
{
createGeometry(geometryType);
}
m_geometries[geometryType].appendFaultPartsToModel(model);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirViewPartMgr::appendFaultsDynamicGeometryPartsToModel(cvf::ModelBasicList* model, ReservoirGeometryCacheType geometryType, size_t frameIndex)
{
if (geometryType == PROPERTY_FILTERED)
{
m_propFilteredGeometryFrames[frameIndex]->appendFaultPartsToModel(model);
}
else if (geometryType == PROPERTY_FILTERED_WELL_CELLS)
{
m_propFilteredWellGeometryFrames[frameIndex]->appendFaultPartsToModel(model);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivReservoirViewPartMgr::ReservoirGeometryCacheType RivReservoirViewPartMgr::geometryTypeForFaultLabels(const std::vector<ReservoirGeometryCacheType>& geometryTypes) const
{
bool hasInactive = false;
for (size_t i = 0; i < geometryTypes.size(); i++)
{
if (geometryTypes[i] == PROPERTY_FILTERED)
{
return PROPERTY_FILTERED;
}
if (geometryTypes[i] == RANGE_FILTERED)
{
return RANGE_FILTERED;
}
if (geometryTypes[i] == INACTIVE)
{
hasInactive = true;
}
}
if (hasInactive)
{
return INACTIVE;
}
return ACTIVE;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirViewPartMgr::appendFaultLabelsStaticGeometryPartsToModel(cvf::ModelBasicList* model, ReservoirGeometryCacheType geometryType)
{
m_geometries[geometryType].appendFaultLabelPartsToModel(model);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirViewPartMgr::appendFaultLabelsDynamicGeometryPartsToModel(cvf::ModelBasicList* model, ReservoirGeometryCacheType geometryType, size_t frameIndex)
{
m_propFilteredGeometryFrames[frameIndex]->appendFaultLabelPartsToModel(model);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivReservoirViewPartMgr::setFaultForceVisibilityForGeometryType(ReservoirGeometryCacheType geometryType, bool forceVisibility)
{
m_geometries[geometryType].setFaultForceVisibility(forceVisibility);
}

View File

@@ -68,6 +68,18 @@ public:
void updateCellEdgeResultColor(ReservoirGeometryCacheType geometryType, size_t timeStepIndex,
RimResultSlot* cellResultSlot, RimCellEdgeResultSlot* cellEdgeResultSlot);
// Faults
void appendFaultsStaticGeometryPartsToModel(cvf::ModelBasicList* model, ReservoirGeometryCacheType geometryType);
void appendFaultsDynamicGeometryPartsToModel(cvf::ModelBasicList* model, ReservoirGeometryCacheType geometryType, size_t frameIndex);
void updateFaultColors(ReservoirGeometryCacheType geometryType, size_t timeStepIndex, RimResultSlot* cellResultSlot);
// Fault labels
ReservoirGeometryCacheType geometryTypeForFaultLabels(const std::vector<ReservoirGeometryCacheType>& geometryTypes) const;
void appendFaultLabelsStaticGeometryPartsToModel(cvf::ModelBasicList* model, ReservoirGeometryCacheType geometryType);
void appendFaultLabelsDynamicGeometryPartsToModel(cvf::ModelBasicList* model, ReservoirGeometryCacheType geometryType, size_t frameIndex);
void setFaultForceVisibilityForGeometryType(ReservoirGeometryCacheType geometryType, bool forceVisibility);
private:
void createGeometry(ReservoirGeometryCacheType geometryType);
void computeVisibility(cvf::UByteArray* cellVisibility, ReservoirGeometryCacheType geometryType, RigGridBase* grid, size_t gridIdx);
@@ -85,6 +97,7 @@ private:
RivReservoirPartMgr * reservoirPartManager(ReservoirGeometryCacheType geometryType, size_t timeStepIndex );
private:
caf::FixedArray<RivReservoirPartMgr, PROPERTY_FILTERED> m_geometries;
caf::FixedArray<bool, PROPERTY_FILTERED> m_geometriesNeedsRegen;

View File

@@ -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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RivSourceInfo.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RivSourceInfo::hasCellIndices() const
{
return m_cellIndices.notNull();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RivSourceInfo::hasNNCIndices() const
{
return m_NNCIndices.notNull();
}

View File

@@ -0,0 +1,37 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfBase.h"
#include "cvfObject.h"
#include "cvfArray.h"
#include "cvfStructGrid.h"
class RivSourceInfo : public cvf::Object
{
public:
bool hasCellIndices() const;
bool hasNNCIndices() const;
public:
cvf::ref<cvf::Array<size_t> > m_cellIndices;
cvf::ref<cvf::Array<cvf::StructGridInterface::FaceType> > m_faceTypes;
cvf::ref<cvf::Array<size_t> > m_NNCIndices;
};

View File

@@ -174,10 +174,10 @@ void RivWellHeadPartMgr::buildWellHeadParts(size_t frameIndex)
if (pipeSurface.notNull())
{
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName("RivWellHeadPartMgr: surface " + cvfqt::Utils::fromQString(well->name()));
part->setName("RivWellHeadPartMgr: surface " + cvfqt::Utils::toString(well->name()));
part->setDrawable(pipeSurface.p());
caf::SurfaceEffectGenerator surfaceGen(cvf::Color4f(well->wellPipeColor()), true);
caf::SurfaceEffectGenerator surfaceGen(cvf::Color4f(well->wellPipeColor()), caf::PO_1);
cvf::ref<cvf::Effect> eff = surfaceGen.generateEffect();
part->setEffect(eff.p());
@@ -188,7 +188,7 @@ void RivWellHeadPartMgr::buildWellHeadParts(size_t frameIndex)
if (centerLineDrawable.notNull())
{
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName("RivWellHeadPartMgr: centerline " + cvfqt::Utils::fromQString(well->name()));
part->setName("RivWellHeadPartMgr: centerline " + cvfqt::Utils::toString(well->name()));
part->setDrawable(centerLineDrawable.p());
caf::MeshEffectGenerator meshGen(well->wellPipeColor());
@@ -249,7 +249,7 @@ void RivWellHeadPartMgr::buildWellHeadParts(size_t frameIndex)
{
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName("RivWellHeadPartMgr: arrow " + cvfqt::Utils::fromQString(well->name()));
part->setName("RivWellHeadPartMgr: arrow " + cvfqt::Utils::toString(well->name()));
part->setDrawable(geo1.p());
cvf::Color4f headColor(cvf::Color3::GRAY);
@@ -273,7 +273,7 @@ void RivWellHeadPartMgr::buildWellHeadParts(size_t frameIndex)
}
}
caf::SurfaceEffectGenerator surfaceGen(headColor, true);
caf::SurfaceEffectGenerator surfaceGen(headColor, caf::PO_1);
cvf::ref<cvf::Effect> eff = surfaceGen.generateEffect();
part->setEffect(eff.p());
@@ -292,7 +292,7 @@ void RivWellHeadPartMgr::buildWellHeadParts(size_t frameIndex)
drawableText->setVerticalAlignment(cvf::TextDrawer::CENTER);
drawableText->setTextColor(m_rimReservoirView->wellCollection()->wellLabelColor());
cvf::String cvfString = cvfqt::Utils::fromQString(well->name());
cvf::String cvfString = cvfqt::Utils::toString(well->name());
cvf::Vec3f textCoord(textPosition);
drawableText->addText(cvfString, textCoord);

View File

@@ -75,7 +75,7 @@ RivWellPathPartMgr::RivWellPathPartMgr(RimWellPathCollection* wellPathCollection
m_scalarMapper = scalarMapper;
caf::ScalarMapperEffectGenerator surfEffGen(scalarMapper.p(), true);
caf::ScalarMapperEffectGenerator surfEffGen(scalarMapper.p(), caf::PO_1);
m_scalarMapperSurfaceEffect = surfEffGen.generateEffect();
caf::ScalarMapperMeshEffectGenerator meshEffGen(scalarMapper.p());
@@ -161,7 +161,7 @@ void RivWellPathPartMgr::buildWellPathParts(cvf::Vec3d displayModelOffset, doubl
pbd.m_surfacePart->setDrawable(pbd.m_surfaceDrawable.p());
//printf("Well Path triangleCount = %i (%i points in well path)\n", pbd.m_surfaceDrawable->triangleCount(), wellPathGeometry->m_wellPathPoints.size());
caf::SurfaceEffectGenerator surfaceGen(cvf::Color4f(m_rimWellPath->wellPathColor()), true);
caf::SurfaceEffectGenerator surfaceGen(cvf::Color4f(m_rimWellPath->wellPathColor()), caf::PO_1);
cvf::ref<cvf::Effect> eff = surfaceGen.generateEffect();
pbd.m_surfacePart->setEffect(eff.p());
@@ -199,7 +199,7 @@ void RivWellPathPartMgr::buildWellPathParts(cvf::Vec3d displayModelOffset, doubl
drawableText->setVerticalAlignment(cvf::TextDrawer::CENTER);
drawableText->setTextColor(m_wellPathCollection->wellPathLabelColor());
cvf::String cvfString = cvfqt::Utils::fromQString(m_rimWellPath->name());
cvf::String cvfString = cvfqt::Utils::toString(m_rimWellPath->name());
cvf::Vec3f textCoord(textPosition);
drawableText->addText(cvfString, textCoord);

View File

@@ -70,7 +70,7 @@ RivWellPipesPartMgr::RivWellPipesPartMgr(RimReservoirView* reservoirView, RimWel
m_scalarMapper = scalarMapper;
caf::ScalarMapperEffectGenerator surfEffGen(scalarMapper.p(), true);
caf::ScalarMapperEffectGenerator surfEffGen(scalarMapper.p(), caf::PO_1);
m_scalarMapperSurfaceEffect = surfEffGen.generateEffect();
caf::ScalarMapperMeshEffectGenerator meshEffGen(scalarMapper.p());
@@ -139,7 +139,7 @@ void RivWellPipesPartMgr::buildWellPipeParts()
pbd.m_surfacePart = new cvf::Part;
pbd.m_surfacePart->setDrawable(pbd.m_surfaceDrawable.p());
caf::SurfaceEffectGenerator surfaceGen(cvf::Color4f(m_rimWell->wellPipeColor()), true);
caf::SurfaceEffectGenerator surfaceGen(cvf::Color4f(m_rimWell->wellPipeColor()), caf::PO_1);
cvf::ref<cvf::Effect> eff = surfaceGen.generateEffect();
pbd.m_surfacePart->setEffect(eff.p());

View File

@@ -44,6 +44,8 @@ ${CEE_CURRENT_LIST_DIR}RimStatisticsCaseEvaluator.h
${CEE_CURRENT_LIST_DIR}RimMimeData.h
${CEE_CURRENT_LIST_DIR}RimCommandObject.h
${CEE_CURRENT_LIST_DIR}RimTools.h
${CEE_CURRENT_LIST_DIR}RimFault.h
${CEE_CURRENT_LIST_DIR}RimFaultCollection.h
)
set (SOURCE_GROUP_SOURCE_FILES
@@ -86,6 +88,8 @@ ${CEE_CURRENT_LIST_DIR}RimStatisticsCaseEvaluator.cpp
${CEE_CURRENT_LIST_DIR}RimMimeData.cpp
${CEE_CURRENT_LIST_DIR}RimCommandObject.cpp
${CEE_CURRENT_LIST_DIR}RimTools.cpp
${CEE_CURRENT_LIST_DIR}RimFault.cpp
${CEE_CURRENT_LIST_DIR}RimFaultCollection.cpp
)
list(APPEND CODE_HEADER_FILES

View File

@@ -112,6 +112,7 @@ void Rim3dOverlayInfoConfig::update3DInfo()
QString zScale;
QString propName;
QString cellEdgeName;
QString faultCellResultMapping;
if (m_reservoirView->eclipseCase() && m_reservoirView->eclipseCase()->reservoirData() && m_reservoirView->eclipseCase()->reservoirData()->mainGrid())
@@ -155,6 +156,33 @@ void Rim3dOverlayInfoConfig::update3DInfo()
//infoText += QString("<blockquote><pre>Min: %1 P10: %2 Mean: %3 \n P90: %4 Max: %5 </pre></blockquote>").arg(min).arg(p10).arg(mean).arg(p90).arg(max);
infoText += QString("<table border=0 cellspacing=5 ><tr><td>Min</td><td>P10</td> <td>Mean</td> <td>P90</td> <td>Max</td> </tr>"
"<tr><td>%1</td><td> %2</td><td> %3</td><td> %4</td><td> %5 </td></tr></table>").arg(min).arg(p10).arg(mean).arg(p90).arg(max);
if (m_reservoirView->faultCollection()->showResultsOnFaults())
{
QString faultMapping;
bool isShowingGrid = m_reservoirView->faultCollection()->isGridVisualizationMode();
if (!isShowingGrid)
{
if (m_reservoirView->faultCollection()->faultResult() == RimFaultCollection::FAULT_BACK_FACE_CULLING)
{
faultMapping = "Show values from cells behind fault";
}
else if (m_reservoirView->faultCollection()->faultResult() == RimFaultCollection::FAULT_FRONT_FACE_CULLING)
{
faultMapping = "Show values from cells in front of fault";
}
else
{
faultMapping = "Show values from cells in front and behind fault";
}
}
else
{
faultMapping = "Show values from cells in front and behind fault";
}
infoText += QString("<b>Fault results: </b> %1<br>").arg(faultMapping);
}
}

View File

@@ -182,15 +182,8 @@ RigMainGrid* RimAnalysisModels::registerCaseInGridCollection(RigCaseData* rigEcl
// This is the first insertion of this grid, compute cached data
rigEclipseCase->mainGrid()->computeCachedData();
std::vector<RigGridBase*> grids;
rigEclipseCase->allGrids(&grids);
size_t i;
for (i = 0; i < grids.size(); i++)
{
grids[i]->computeFaults();
}
rigEclipseCase->mainGrid()->calculateFaults();
equalGrid = rigEclipseCase->mainGrid();
}
@@ -212,3 +205,27 @@ void RimAnalysisModels::insertCaseInCaseGroup(RimIdenticalGridCaseGroup* caseGro
caseGroup->addCase(rimReservoir);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimAnalysisModels::recomputeStatisticsForAllCaseGroups()
{
const size_t numCaseGroups = caseGroups.size();
for (size_t caseGrpIdx = 0; caseGrpIdx < numCaseGroups; ++caseGrpIdx)
{
RimIdenticalGridCaseGroup* caseGroup = caseGroups[caseGrpIdx];
RimCaseCollection* statisticsCaseCollection = caseGroup->statisticsCaseCollection;
const size_t numStatisticsCases = statisticsCaseCollection->reservoirs.size();
for (size_t caseIdx = 0; caseIdx < numStatisticsCases; caseIdx++)
{
RimStatisticsCase* statisticsCase = dynamic_cast<RimStatisticsCase*>(statisticsCaseCollection->reservoirs[caseIdx]);
if (statisticsCase)
{
statisticsCase->clearComputedStatistics();
statisticsCase->computeStatistics();
}
}
}
}

View File

@@ -49,6 +49,8 @@ public:
void moveEclipseCaseIntoCaseGroup(RimCase* rimReservoir);
void removeCaseFromAllGroups(RimCase* rimReservoir);
void recomputeStatisticsForAllCaseGroups();
private:
RigMainGrid* registerCaseInGridCollection(RigCaseData* rigEclipseCase);
cvf::ref<RigGridManager> m_gridCollection;

View File

@@ -60,6 +60,7 @@
#include "RimCaseCollection.h"
#include "RimOilField.h"
#include "RimAnalysisModels.h"
#include "cafProgressInfo.h"
CAF_PDM_SOURCE_INIT(RimCase, "RimReservoir");
@@ -83,6 +84,8 @@ RimCase::RimCase()
CAF_PDM_InitField(&flipXAxis, "FlipXAxis", false, "Flip X Axis", "", "", "");
CAF_PDM_InitField(&flipYAxis, "FlipYAxis", false, "Flip Y Axis", "", "", "");
CAF_PDM_InitFieldNoDefault(&filesContainingFaults, "FilesContainingFaults", "", "", "", "");
filesContainingFaults.setUiHidden(true);
// Obsolete field
CAF_PDM_InitField(&caseName, "CaseName", QString(), "Obsolete", "", "" ,"");
@@ -312,18 +315,18 @@ void RimCase::computeCachedData()
RigCaseData* rigEclipseCase = reservoirData();
if (rigEclipseCase)
{
caf::ProgressInfo pInf(30, "");
pInf.setNextProgressIncrement(1);
rigEclipseCase->computeActiveCellBoundingBoxes();
pInf.incrementProgress();
pInf.setNextProgressIncrement(10);
rigEclipseCase->mainGrid()->computeCachedData();
pInf.incrementProgress();
std::vector<RigGridBase*> grids;
rigEclipseCase->allGrids(&grids);
size_t i;
for (i = 0; i < grids.size(); i++)
{
grids[i]->computeFaults();
}
pInf.setProgressDescription("Calculating faults");
rigEclipseCase->mainGrid()->calculateFaults();
pInf.incrementProgress();
}
}

View File

@@ -53,6 +53,8 @@ public:
caf::PdmPointersField<RimReservoirView*> reservoirViews;
caf::PdmField<bool> flipXAxis;
caf::PdmField<bool> flipYAxis;
caf::PdmField<std::vector<QString> > filesContainingFaults;
virtual bool openEclipseGridFile() { return false;}; // Should be pure virtual but PDM does not allow that.

View File

@@ -41,7 +41,7 @@ RimCellEdgeResultSlot::RimCellEdgeResultSlot()
{
CAF_PDM_InitObject("Cell Edge Result", "", "", "");
CAF_PDM_InitFieldNoDefault(&resultVariable, "CellEdgeVariable", "Result variable", "", "", "");
CAF_PDM_InitFieldNoDefault(&resultVariable, "CellEdgeVariable", "Result property", "", "", "");
CAF_PDM_InitField(&useXVariable, "UseXVariable", true, "Use X values", "", "", "");
CAF_PDM_InitField(&useYVariable, "UseYVariable", true, "Use Y values", "", "", "");
CAF_PDM_InitField(&useZVariable, "UseZVariable", true, "Use Z values", "", "", "");
@@ -154,6 +154,8 @@ QList<caf::PdmOptionItemInfo> RimCellEdgeResultSlot::calculateValueOptions(const
int i;
for (i = 0; i < varList.size(); ++i)
{
if (varList[i].compare(RimDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0) continue;
size_t cubeFaceIdx;
for (cubeFaceIdx = 0; cubeFaceIdx < EdgeFaceEnum::size(); ++cubeFaceIdx)
{
@@ -223,6 +225,8 @@ QStringList RimCellEdgeResultSlot::findResultVariableNames()
int i;
for (i = 0; i < varList.size(); ++i)
{
if (varList[i].compare(RimDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0) continue;
if (varList[i].contains(resultVariable))
{
varNames.append(varList[i]);

View File

@@ -40,5 +40,8 @@ public:
};
static QString undefinedResultName() { return "None"; }
static QString undefinedGridFaultName() { return "Undefined grid faults"; }
static QString combinedTransmissibilityResultName() { return "TRANSXYZ"; }
};

View File

@@ -0,0 +1,122 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimFault.h"
#include "RigFault.h"
#include "RimReservoirView.h"
#include "RimResultSlot.h"
#include "RimCellEdgeResultSlot.h"
#include "Rim3dOverlayInfoConfig.h"
#include "RimCellPropertyFilterCollection.h"
#include "RimCellRangeFilterCollection.h"
#include "RimWellCollection.h"
CAF_PDM_SOURCE_INIT(RimFault, "Fault");
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFault::RimFault()
{
CAF_PDM_InitObject("RimFault", ":/draw_style_faults_24x24.png", "", "");
CAF_PDM_InitFieldNoDefault(&name, "FaultName", "Name", "", "", "");
name.setUiHidden(true);
name.setUiReadOnly(true);
CAF_PDM_InitField(&showFault, "ShowFault", true, "Show fault", "", "", "");
showFault.setUiHidden(true);
CAF_PDM_InitField(&faultColor, "Color", cvf::Color3f(0.588f, 0.588f, 0.804f), "Fault color", "", "", "");
m_rigFault = NULL;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFault::~RimFault()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmFieldHandle* RimFault::userDescriptionField()
{
return &name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFault::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue)
{
if (&showFault == changedField)
{
this->updateUiIconFromState(showFault);
RimReservoirView* reservoirView = NULL;
this->firstAncestorOfType(reservoirView);
if (reservoirView)
{
reservoirView->scheduleCreateDisplayModelAndRedraw();
}
}
if (&faultColor == changedField)
{
RimReservoirView* reservoirView = NULL;
this->firstAncestorOfType(reservoirView);
if (reservoirView)
{
reservoirView->scheduleCreateDisplayModelAndRedraw();
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmFieldHandle* RimFault::objectToggleField()
{
return &showFault;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFault::setFaultGeometry(const RigFault* faultGeometry)
{
m_rigFault = faultGeometry;
this->name = faultGeometry->name();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RigFault* RimFault::faultGeometry() const
{
return m_rigFault;
}

View File

@@ -0,0 +1,59 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmPointer.h"
#include "cvfBase.h"
#include "cvfColor3.h"
#include "cafPdmFieldCvfColor.h"
class RigFault;
//==================================================================================================
///
///
//==================================================================================================
class RimFault : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
RimFault();
virtual ~RimFault();
void setFaultGeometry(const RigFault* faultGeometry);
const RigFault* faultGeometry() const;
virtual caf::PdmFieldHandle* userDescriptionField();
virtual caf::PdmFieldHandle* objectToggleField();
virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue);
caf::PdmField<bool> showFault;
caf::PdmField<QString> name;
caf::PdmField<cvf::Color3f> faultColor;
private:
const RigFault* m_rigFault;
};

View File

@@ -0,0 +1,287 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimFaultCollection.h"
#include "cafAppEnum.h"
#include "cafPdmFieldCvfColor.h"
#include "cafPdmFieldCvfMat4d.h"
#include "RimReservoirView.h"
#include "RimResultSlot.h"
#include "RimCellRangeFilterCollection.h"
#include "RimCellPropertyFilterCollection.h"
#include "RimWellCollection.h"
#include "Rim3dOverlayInfoConfig.h"
#include "RimCellEdgeResultSlot.h"
#include "RiaApplication.h"
#include "RiaPreferences.h"
#include "RimCase.h"
#include "RimReservoirCellResultsCacher.h"
#include "RigCaseData.h"
#include "RivColorTableArray.h"
#include "RiuMainWindow.h"
namespace caf
{
template<>
void AppEnum< RimFaultCollection::FaultFaceCullingMode >::setUp()
{
addItem(RimFaultCollection::FAULT_BACK_FACE_CULLING, "FAULT_BACK_FACE_CULLING", "Cell behind fault");
addItem(RimFaultCollection::FAULT_FRONT_FACE_CULLING, "FAULT_FRONT_FACE_CULLING", "Cell in front of fault");
addItem(RimFaultCollection::FAULT_NO_FACE_CULLING, "FAULT_NO_FACE_CULLING", "Show both");
setDefault(RimFaultCollection::FAULT_NO_FACE_CULLING);
}
}
CAF_PDM_SOURCE_INIT(RimFaultCollection, "Faults");
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFaultCollection::RimFaultCollection()
{
CAF_PDM_InitObject("Faults", ":/draw_style_faults_24x24.png", "", "");
RiaPreferences* prefs = RiaApplication::instance()->preferences();
CAF_PDM_InitField(&showFaultCollection, "Active", true, "Active", "", "", "");
showFaultCollection.setUiHidden(true);
CAF_PDM_InitField(&showGeometryDetectedFaults, "ShowGeometryDetectedFaults", false, "Show geometry detected faults", "", "", "");
showGeometryDetectedFaults.setUiHidden(true);
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(&showFaultsOutsideFilters,"ShowFaultsOutsideFilters", true, "Show faults outside filters", "", "", "");
CAF_PDM_InitField(&faultResult, "FaultFaceCulling", caf::AppEnum<RimFaultCollection::FaultFaceCullingMode>(RimFaultCollection::FAULT_BACK_FACE_CULLING), "Dynamic Face Selection", "", "", "");
CAF_PDM_InitField(&showFaultLabel, "ShowFaultLabel", false, "Show labels", "", "", "");
cvf::Color3f defWellLabelColor = RiaApplication::instance()->preferences()->defaultWellLabelColor();
CAF_PDM_InitField(&faultLabelColor, "FaultLabelColor", defWellLabelColor, "Label color", "", "", "");
CAF_PDM_InitFieldNoDefault(&faults, "Faults", "Faults", "", "", "");
m_reservoirView = NULL;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFaultCollection::~RimFaultCollection()
{
faults.deleteAllChildObjects();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFaultCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue)
{
if (&showFaultCollection == changedField)
{
this->updateUiIconFromState(showFaultCollection);
}
if (&faultLabelColor == changedField)
{
m_reservoirView->scheduleReservoirGridGeometryRegen();
}
if (&showGeometryDetectedFaults == changedField ||
&showFaultFaces == changedField ||
&showOppositeFaultFaces == changedField ||
&showNNCs == changedField ||
&showFaultCollection == changedField ||
&showFaultLabel == changedField ||
&showFaultsOutsideFilters == changedField ||
&faultLabelColor == changedField ||
&faultResult == changedField ||
&showResultsOnFaults == changedField
)
{
if (m_reservoirView)
{
m_reservoirView->scheduleCreateDisplayModelAndRedraw();
}
}
if (&showFaultLabel == changedField)
{
RiuMainWindow::instance()->refreshDrawStyleActions();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFaultCollection::setReservoirView(RimReservoirView* ownerReservoirView)
{
m_reservoirView = ownerReservoirView;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmFieldHandle* RimFaultCollection::objectToggleField()
{
return &showFaultCollection;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFault* RimFaultCollection::findFaultByName(QString name)
{
for (size_t i = 0; i < this->faults().size(); ++i)
{
if (this->faults()[i]->name() == name)
{
return this->faults()[i];
}
}
return NULL;
}
//--------------------------------------------------------------------------------------------------
/// A comparing function used to sort Faults in the RimFaultCollection::syncronizeFaults() method
//--------------------------------------------------------------------------------------------------
bool faultComparator(const cvf::ref<RigFault>& a, const cvf::ref<RigFault>& b)
{
CVF_TIGHT_ASSERT(a.notNull() && b.notNull());
int compareValue = a->name().compare(b->name(), Qt::CaseInsensitive);
return (compareValue < 0);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFaultCollection::syncronizeFaults()
{
if (!(m_reservoirView && m_reservoirView->eclipseCase() && m_reservoirView->eclipseCase()->reservoirData()) ) return;
cvf::ref<cvf::Color3fArray> partColors = RivColorTableArray::colorTableArray();
const cvf::Collection<RigFault> constRigFaults = m_reservoirView->eclipseCase()->reservoirData()->mainGrid()->faults();
cvf::Collection<RigFault> rigFaults;
{
cvf::Collection<RigFault> sortedFaults(constRigFaults);
std::sort(sortedFaults.begin(), sortedFaults.end(), faultComparator);
cvf::ref<RigFault> undefinedFaults;
for (size_t i = 0; i < sortedFaults.size(); i++)
{
if (sortedFaults[i]->name().compare(RimDefines::undefinedGridFaultName(), Qt::CaseInsensitive) == 0)
{
undefinedFaults = sortedFaults[i];
}
}
if (undefinedFaults.notNull())
{
sortedFaults.erase(undefinedFaults.p());
rigFaults.push_back(undefinedFaults.p());
}
for (size_t i = 0; i < sortedFaults.size(); i++)
{
rigFaults.push_back(sortedFaults[i].p());
}
}
// Find faults with
std::vector<caf::PdmPointer<RimFault> > newFaults;
// Find corresponding fault from data model, or create a new
for (size_t fIdx = 0; fIdx < rigFaults.size(); ++fIdx)
{
RimFault* rimFault = this->findFaultByName(rigFaults[fIdx]->name());
if (!rimFault)
{
rimFault = new RimFault();
rimFault->faultColor = partColors->get(fIdx % partColors->size());
}
rimFault->setFaultGeometry(rigFaults[fIdx].p());
newFaults.push_back(rimFault);
}
this->faults().clear();
this->faults().insert(0, newFaults);
QString toolTip = QString("Fault count (%1)").arg(newFaults.size());
setUiToolTip(toolTip);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimFaultCollection::isGridVisualizationMode() const
{
CVF_ASSERT(m_reservoirView);
return m_reservoirView->isGridVisualizationMode();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFaultCollection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering)
{
bool isGridVizMode = isGridVisualizationMode();
faultResult.setUiReadOnly(isGridVizMode);
showFaultFaces.setUiReadOnly(isGridVizMode);
showOppositeFaultFaces.setUiReadOnly(isGridVizMode);
caf::PdmUiGroup* labs = uiOrdering.addNewGroup("Fault Labels");
labs->add(&showFaultLabel);
labs->add(&faultLabelColor);
caf::PdmUiGroup* adv = uiOrdering.addNewGroup("Fault Options");
adv->add(&showFaultsOutsideFilters);
adv->add(&showResultsOnFaults);
adv->add(&showNNCs);
caf::PdmUiGroup* ffviz = uiOrdering.addNewGroup("Fault Face Visibility");
ffviz->add(&showFaultFaces);
ffviz->add(&showOppositeFaultFaces);
ffviz->add(&faultResult);
}

View File

@@ -0,0 +1,88 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmPointer.h"
#include "cafAppEnum.h"
#include <QString>
#include "cvfBase.h"
#include "cvfColor3.h"
#include "RimFault.h"
class RimReservoirView;
//==================================================================================================
///
///
//==================================================================================================
class RimFaultCollection : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
enum FaultFaceCullingMode
{
FAULT_BACK_FACE_CULLING,
FAULT_FRONT_FACE_CULLING,
FAULT_NO_FACE_CULLING
};
public:
RimFaultCollection();
virtual ~RimFaultCollection();
void setReservoirView(RimReservoirView* ownerReservoirView);
void syncronizeFaults();
bool isGridVisualizationMode() const;
caf::PdmField<bool> showGeometryDetectedFaults; // Obsolete, to be removed
caf::PdmField<bool> showFaultFaces;
caf::PdmField<bool> showOppositeFaultFaces;
caf::PdmField<bool> showFaultsOutsideFilters;
caf::PdmField<bool> showNNCs;
caf::PdmField<bool> showResultsOnFaults;
caf::PdmField<caf::AppEnum< FaultFaceCullingMode > > faultResult;
caf::PdmField<bool> showFaultLabel;
caf::PdmField<cvf::Color3f> faultLabelColor;
caf::PdmField<bool> showFaultCollection;
caf::PdmPointersField<RimFault*> faults;
virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue);
virtual caf::PdmFieldHandle* objectToggleField();
private:
RimFault* findFaultByName(QString name);
virtual void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering );
private:
RimReservoirView* m_reservoirView;
};

View File

@@ -103,9 +103,11 @@ void RimInputCase::openDataFileSet(const QStringList& fileNames)
// First find and read the grid data
if (this->reservoirData()->mainGrid()->gridPointDimensions() == cvf::Vec3st(0,0,0))
{
RiaPreferences* prefs = RiaApplication::instance()->preferences();
for (int i = 0; i < fileNames.size(); i++)
{
if (RifEclipseInputFileTools::openGridFile(fileNames[i], this->reservoirData()))
if (RifEclipseInputFileTools::openGridFile(fileNames[i], this->reservoirData(), prefs->readFaultData()))
{
m_gridFileName = fileNames[i];
@@ -188,8 +190,11 @@ bool RimInputCase::openEclipseGridFile()
}
else
{
cvf::ref<RigCaseData> eclipseCase = new RigCaseData;
RiaPreferences* prefs = RiaApplication::instance()->preferences();
readerInterface = new RifReaderEclipseInput;
readerInterface->readFaultData(prefs->readFaultData());
cvf::ref<RigCaseData> eclipseCase = new RigCaseData;
if (!readerInterface->open(m_gridFileName, eclipseCase.p()))
{
return false;
@@ -262,7 +267,9 @@ void RimInputCase::loadAndSyncronizeInputProperties()
if (isExistingFile)
{
std::vector< RifKeywordAndFilePos > fileKeywords = RifEclipseInputFileTools::findKeywordsOnFile(filenames[i]);
std::vector< RifKeywordAndFilePos > fileKeywords;
RifEclipseInputFileTools::findKeywordsOnFile(filenames[i], fileKeywords);
for_all(fileKeywords, fkIt) fileKeywordSet.insert(fileKeywords[fkIt].keyword);
}

View File

@@ -727,6 +727,16 @@ size_t RimReservoirCellResultsStorage::storedResultsCount()
return m_resultCacheMetaData.size();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimReservoirCellResultsStorage::createCombinedTransmissibilityResults()
{
if (!m_cellResults) return;
m_cellResults->createCombinedTransmissibilityResult();
}
CAF_PDM_SOURCE_INIT(RimReservoirCellResultsStorageEntryInfo, "ResultStorageEntryInfo");

View File

@@ -51,6 +51,7 @@ public:
RifReaderInterface* readerInterface();
void loadOrComputeSOIL();
void createCombinedTransmissibilityResults();
void computeDepthRelatedResults();
size_t findOrLoadScalarResultForTimeStep(RimDefines::ResultCatType type, const QString& resultName, size_t timeStepIndex);

View File

@@ -73,6 +73,7 @@
#include <limits.h>
#include "cafCeetronPlusNavigation.h"
#include "RimFaultCollection.h"
namespace caf {
@@ -99,11 +100,6 @@ void caf::AppEnum< RimReservoirView::SurfaceModeType >::setUp()
const cvf::uint surfaceBit = 0x00000001;
const cvf::uint meshSurfaceBit = 0x00000002;
const cvf::uint faultBit = 0x00000004;
const cvf::uint meshFaultBit = 0x00000008;
CAF_PDM_SOURCE_INIT(RimReservoirView, "ReservoirView");
//--------------------------------------------------------------------------------------------------
@@ -145,6 +141,9 @@ RimReservoirView::RimReservoirView()
CAF_PDM_InitFieldNoDefault(&wellCollection, "WellCollection", "Simulation Wells", "", "", "");
wellCollection = new RimWellCollection;
CAF_PDM_InitFieldNoDefault(&faultCollection, "FaultCollection", "Faults", "", "", "");
faultCollection = new RimFaultCollection;
CAF_PDM_InitFieldNoDefault(&rangeFilterCollection, "RangeFilters", "Range Filters", "", "", "");
rangeFilterCollection = new RimCellRangeFilterCollection();
rangeFilterCollection->setReservoirView(this);
@@ -184,6 +183,8 @@ RimReservoirView::RimReservoirView()
m_pipesPartManager = new RivReservoirPipesPartMgr(this);
m_reservoir = NULL;
m_previousGridModeMeshLinesWasFaults = false;
}
//--------------------------------------------------------------------------------------------------
@@ -198,6 +199,7 @@ RimReservoirView::~RimReservoirView()
delete rangeFilterCollection();
delete propertyFilterCollection();
delete wellCollection();
delete faultCollection();
if (m_viewer)
{
@@ -469,11 +471,15 @@ void RimReservoirView::fieldChangedByUi(const caf::PdmFieldHandle* changedField,
}
else if (changedField == &meshMode)
{
createDisplayModel();
updateDisplayModelVisibility();
RiuMainWindow::instance()->refreshDrawStyleActions();
}
else if (changedField == &surfaceMode)
{
createDisplayModel();
updateDisplayModelVisibility();
RiuMainWindow::instance()->refreshDrawStyleActions();
}
else if (changedField == &name)
{
@@ -568,7 +574,7 @@ void RimReservoirView::createDisplayModel()
// For property filtered geometry : just set all the models as empty scenes
// updateCurrentTimeStep requests the actual parts
if (! this->propertyFilterCollection()->hasActiveFilters())
if (!this->propertyFilterCollection()->hasActiveFilters())
{
std::vector<RivReservoirViewPartMgr::ReservoirGeometryCacheType> geometryTypesToAdd;
@@ -607,7 +613,7 @@ void RimReservoirView::createDisplayModel()
geometryTypesToAdd.push_back(RivReservoirViewPartMgr::INACTIVE);
}
}
size_t frameIdx;
for (frameIdx = 0; frameIdx < frameModels.size(); ++frameIdx)
{
@@ -622,6 +628,29 @@ void RimReservoirView::createDisplayModel()
m_visibleGridParts = geometryTypesToAdd;
}
if (!this->propertyFilterCollection()->hasActiveFilters() || faultCollection()->showFaultsOutsideFilters)
{
std::vector<RivReservoirViewPartMgr::ReservoirGeometryCacheType> faultGeometryTypesToAppend = visibleFaultParts();
RivReservoirViewPartMgr::ReservoirGeometryCacheType faultLabelType = m_reservoirGridPartManager->geometryTypeForFaultLabels(faultGeometryTypesToAppend);
for (size_t frameIdx = 0; frameIdx < frameModels.size(); ++frameIdx)
{
for (size_t gtIdx = 0; gtIdx < faultGeometryTypesToAppend.size(); ++gtIdx)
{
m_reservoirGridPartManager->appendFaultsStaticGeometryPartsToModel(frameModels[frameIdx].p(), faultGeometryTypesToAppend[gtIdx]);
}
m_reservoirGridPartManager->appendFaultLabelsStaticGeometryPartsToModel(frameModels[frameIdx].p(), faultLabelType);
}
updateFaultForcedVisibility();
}
this->updateFaultColors();
// Compute triangle count, Debug only
@@ -697,6 +726,26 @@ void RimReservoirView::updateCurrentTimeStep()
geometriesToRecolor.push_back( RivReservoirViewPartMgr::PROPERTY_FILTERED_WELL_CELLS);
m_reservoirGridPartManager->appendDynamicGeometryPartsToModel(frameParts.p(), RivReservoirViewPartMgr::PROPERTY_FILTERED_WELL_CELLS, m_currentTimeStep, gridIndices);
if (faultCollection()->showFaultsOutsideFilters)
{
std::vector<RivReservoirViewPartMgr::ReservoirGeometryCacheType> faultGeometryTypesToAppend = visibleFaultParts();
for (size_t i = 0; i < faultGeometryTypesToAppend.size(); i++)
{
m_reservoirGridPartManager->appendFaultsStaticGeometryPartsToModel(frameParts.p(), faultGeometryTypesToAppend[i]);
}
RivReservoirViewPartMgr::ReservoirGeometryCacheType faultLabelType = m_reservoirGridPartManager->geometryTypeForFaultLabels(faultGeometryTypesToAppend);
m_reservoirGridPartManager->appendFaultLabelsStaticGeometryPartsToModel(frameParts.p(), faultLabelType);
}
else
{
m_reservoirGridPartManager->appendFaultsDynamicGeometryPartsToModel(frameParts.p(), RivReservoirViewPartMgr::PROPERTY_FILTERED, m_currentTimeStep);
m_reservoirGridPartManager->appendFaultLabelsDynamicGeometryPartsToModel(frameParts.p(), RivReservoirViewPartMgr::PROPERTY_FILTERED, m_currentTimeStep);
m_reservoirGridPartManager->appendFaultsDynamicGeometryPartsToModel(frameParts.p(), RivReservoirViewPartMgr::PROPERTY_FILTERED_WELL_CELLS, m_currentTimeStep);
}
// Set the transparency on all the Wellcell parts before setting the result color
float opacity = static_cast< float> (1 - cvf::Math::clamp(this->wellCollection()->wellCellTransparencyLevel(), 0.0, 1.0));
m_reservoirGridPartManager->updateCellColor(RivReservoirViewPartMgr::PROPERTY_FILTERED_WELL_CELLS, m_currentTimeStep, cvf::Color4f(cvf::Color3f(cvf::Color3::WHITE), opacity));
@@ -710,10 +759,20 @@ void RimReservoirView::updateCurrentTimeStep()
if (this->rangeFilterCollection()->hasActiveFilters() ) // Wells not considered, because we do not have a INACTIVE_WELL_CELLS group yet.
{
m_reservoirGridPartManager->appendStaticGeometryPartsToModel(frameParts.p(), RivReservoirViewPartMgr::RANGE_FILTERED_INACTIVE, gridIndices);
if (!faultCollection()->showFaultsOutsideFilters)
{
m_reservoirGridPartManager->appendFaultsStaticGeometryPartsToModel(frameParts.p(), RivReservoirViewPartMgr::RANGE_FILTERED_INACTIVE);
}
}
else
{
m_reservoirGridPartManager->appendStaticGeometryPartsToModel(frameParts.p(), RivReservoirViewPartMgr::INACTIVE, gridIndices);
m_reservoirGridPartManager->appendStaticGeometryPartsToModel(frameParts.p(), RivReservoirViewPartMgr::INACTIVE, gridIndices);
if (!faultCollection()->showFaultsOutsideFilters)
{
m_reservoirGridPartManager->appendFaultsStaticGeometryPartsToModel(frameParts.p(), RivReservoirViewPartMgr::INACTIVE);
}
}
}
@@ -752,7 +811,6 @@ void RimReservoirView::updateCurrentTimeStep()
geometriesToRecolor.push_back(RivReservoirViewPartMgr::ACTIVE);
geometriesToRecolor.push_back(RivReservoirViewPartMgr::ALL_WELL_CELLS);
}
for (size_t i = 0; i < geometriesToRecolor.size(); ++i)
{
@@ -770,6 +828,8 @@ void RimReservoirView::updateCurrentTimeStep()
}
}
this->updateFaultColors();
// Well pipes and well paths
if (m_viewer)
{
@@ -871,6 +931,7 @@ void RimReservoirView::loadDataAndUpdate()
RimReservoirCellResultsStorage* results = currentGridCellResults();
CVF_ASSERT(results);
results->loadOrComputeSOIL();
results->createCombinedTransmissibilityResults();
}
}
}
@@ -890,6 +951,9 @@ void RimReservoirView::loadDataAndUpdate()
this->propertyFilterCollection()->loadAndInitializePropertyFilters();
this->faultCollection()->setReservoirView(this);
this->faultCollection()->syncronizeFaults();
m_reservoirGridPartManager->clearGeometryCache();
syncronizeWellsWithResults();
@@ -992,7 +1056,7 @@ RiuViewer* RimReservoirView::viewer()
//--------------------------------------------------------------------------------------------------
/// Get pick info text for given part ID, face index, and intersection point
//--------------------------------------------------------------------------------------------------
bool RimReservoirView::pickInfo(size_t gridIndex, size_t cellIndex, const cvf::Vec3d& point, QString* pickInfoText) const
bool RimReservoirView::pickInfo(size_t gridIndex, size_t cellIndex, cvf::StructGridInterface::FaceType face, const cvf::Vec3d& point, QString* pickInfoText) const
{
CVF_ASSERT(pickInfoText);
@@ -1013,7 +1077,16 @@ bool RimReservoirView::pickInfo(size_t gridIndex, size_t cellIndex, const cvf::V
cvf::Vec3d domainCoord = point + eclipseCase->grid(gridIndex)->displayModelOffset();
pickInfoText->sprintf("Hit grid %u, cell [%u, %u, %u], intersection point: [E: %.2f, N: %.2f, Depth: %.2f]", static_cast<unsigned int>(gridIndex), static_cast<unsigned int>(i), static_cast<unsigned int>(j), static_cast<unsigned int>(k), domainCoord.x(), domainCoord.y(), -domainCoord.z());
cvf::StructGridInterface::FaceEnum faceEnum(face);
QString faceText = faceEnum.text();
*pickInfoText = QString("Hit grid %1, cell [%2, %3, %4] face %5, ").arg(gridIndex).arg(i).arg(j).arg(k).arg(faceText);
QString formattedText;
formattedText.sprintf("intersection point: [E: %.2f, N: %.2f, Depth: %.2f]", domainCoord.x(), domainCoord.y(), -domainCoord.z());
*pickInfoText += formattedText;
return true;
}
}
@@ -1023,9 +1096,9 @@ bool RimReservoirView::pickInfo(size_t gridIndex, size_t cellIndex, const cvf::V
}
//--------------------------------------------------------------------------------------------------
/// Get the current scalar value for the display face at the given index
/// Append fault name and result value for the given cell to the string
//--------------------------------------------------------------------------------------------------
void RimReservoirView::appendCellResultInfo(size_t gridIndex, size_t cellIndex, QString* resultInfoText)
void RimReservoirView::appendCellResultInfo(size_t gridIndex, size_t cellIndex, cvf::StructGridInterface::FaceType face, QString* resultInfoText)
{
CVF_ASSERT(resultInfoText);
@@ -1041,7 +1114,29 @@ void RimReservoirView::appendCellResultInfo(size_t gridIndex, size_t cellIndex,
if (cellResult->hasStaticResult())
{
dataAccessObject = eclipseCase->dataAccessObject(grid, porosityModel, 0, this->cellResult()->gridScalarIndex());
if (this->cellResult()->resultVariable().compare(RimDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0)
{
size_t tranX, tranY, tranZ;
if (eclipseCase->results(porosityModel)->findTransmissibilityResults(tranX, tranY, tranZ))
{
cvf::ref<cvf::StructGridScalarDataAccess> dataAccessObjectX = eclipseCase->dataAccessObject(grid, porosityModel, 0, tranX);
cvf::ref<cvf::StructGridScalarDataAccess> dataAccessObjectY = eclipseCase->dataAccessObject(grid, porosityModel, 0, tranY);
cvf::ref<cvf::StructGridScalarDataAccess> dataAccessObjectZ = eclipseCase->dataAccessObject(grid, porosityModel, 0, tranZ);
double scalarValue = dataAccessObjectX->cellScalar(cellIndex);
resultInfoText->append(QString("Tran X : %1\n").arg(scalarValue));
scalarValue = dataAccessObjectY->cellScalar(cellIndex);
resultInfoText->append(QString("Tran Y : %1\n").arg(scalarValue));
scalarValue = dataAccessObjectZ->cellScalar(cellIndex);
resultInfoText->append(QString("Tran Z : %1\n").arg(scalarValue));
}
}
else
{
dataAccessObject = eclipseCase->dataAccessObject(grid, porosityModel, 0, this->cellResult()->gridScalarIndex());
}
}
else
{
@@ -1094,6 +1189,8 @@ void RimReservoirView::appendCellResultInfo(size_t gridIndex, size_t cellIndex,
resultInfoText->append(QString("Well-cell connection info: Well Name: %1 Branch Id: %2 Segment Id: %3\n").arg(singleWellResultData->m_wellName).arg(wellResultCell->m_ertBranchId).arg(wellResultCell->m_ertSegmentId));
}
}
appendFaultName(grid, cellIndex, face, resultInfoText);
}
}
@@ -1104,34 +1201,41 @@ void RimReservoirView::appendCellResultInfo(size_t gridIndex, size_t cellIndex,
void RimReservoirView::updateDisplayModelVisibility()
{
if (m_viewer.isNull()) return;
const cvf::uint uintSurfaceBit = surfaceBit;
const cvf::uint uintMeshSurfaceBit = meshSurfaceBit;
const cvf::uint uintFaultBit = faultBit;
const cvf::uint uintMeshFaultBit = meshFaultBit;
// Initialize the mask to show everything except the the bits controlled here
unsigned int mask = 0xffffffff & ~surfaceBit & ~faultBit & ~meshSurfaceBit & ~meshFaultBit ;
unsigned int mask = 0xffffffff & ~uintSurfaceBit & ~uintFaultBit & ~uintMeshSurfaceBit & ~uintMeshFaultBit ;
// Then turn the appropriate bits on according to the user settings
if (surfaceMode == SURFACE)
{
mask |= surfaceBit;
mask |= faultBit;
mask |= uintSurfaceBit;
mask |= uintFaultBit;
}
else if (surfaceMode == FAULTS)
{
mask |= faultBit;
mask |= uintFaultBit;
}
if (meshMode == FULL_MESH)
{
mask |= meshSurfaceBit;
mask |= meshFaultBit;
mask |= uintMeshSurfaceBit;
mask |= uintMeshFaultBit;
}
else if (meshMode == FAULTS_MESH)
{
mask |= meshFaultBit;
mask |= uintMeshFaultBit;
}
m_viewer->setEnableMask(mask);
m_viewer->update();
faultCollection->updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
@@ -1281,7 +1385,7 @@ void RimReservoirView::updateLegends()
this->cellResult()->legendConfig->setAutomaticRanges(globalMin, globalMax, localMin, localMax);
m_viewer->setColorLegend1(this->cellResult()->legendConfig->legend());
this->cellResult()->legendConfig->legend()->setTitle(cvfqt::Utils::fromQString(QString("Cell Results: \n") + this->cellResult()->resultVariable()));
this->cellResult()->legendConfig->legend()->setTitle(cvfqt::Utils::toString(QString("Cell Results: \n") + this->cellResult()->resultVariable()));
}
else
{
@@ -1301,7 +1405,7 @@ void RimReservoirView::updateLegends()
this->cellEdgeResult()->legendConfig->setAutomaticRanges(globalMin, globalMax, globalMin, globalMax);
m_viewer->setColorLegend2(this->cellEdgeResult()->legendConfig->legend());
this->cellEdgeResult()->legendConfig->legend()->setTitle(cvfqt::Utils::fromQString(QString("Edge Results: \n") + this->cellEdgeResult()->resultVariable));
this->cellEdgeResult()->legendConfig->legend()->setTitle(cvfqt::Utils::toString(QString("Edge Results: \n") + this->cellEdgeResult()->resultVariable));
}
else
@@ -1536,17 +1640,16 @@ void RimReservoirView::updateDisplayModelForWellResults()
//--------------------------------------------------------------------------------------------------
void RimReservoirView::setMeshOnlyDrawstyle()
{
if (surfaceMode == FAULTS || meshMode == FAULTS_MESH)
if (isGridVisualizationMode())
{
surfaceMode = NO_SURFACE;
meshMode = FAULTS_MESH;
meshMode.setValueFromUi(FULL_MESH);
}
else
{
surfaceMode = NO_SURFACE;
meshMode = FULL_MESH;
meshMode.setValueFromUi(FAULTS_MESH);
}
updateDisplayModelVisibility();
surfaceMode.setValueFromUi(NO_SURFACE);
}
//--------------------------------------------------------------------------------------------------
@@ -1554,17 +1657,38 @@ void RimReservoirView::setMeshOnlyDrawstyle()
//--------------------------------------------------------------------------------------------------
void RimReservoirView::setMeshSurfDrawstyle()
{
if (surfaceMode == FAULTS || meshMode == FAULTS_MESH)
if (isGridVisualizationMode())
{
surfaceMode = FAULTS;
meshMode = FAULTS_MESH;
surfaceMode.setValueFromUi(SURFACE);
meshMode.setValueFromUi(FULL_MESH);
}
else
{
surfaceMode = SURFACE;
meshMode = FULL_MESH;
surfaceMode.setValueFromUi(FAULTS);
meshMode.setValueFromUi(FAULTS_MESH);
}
updateDisplayModelVisibility();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimReservoirView::setFaultMeshSurfDrawstyle()
{
// Surf: No Fault Surf
// Mesh -------------
// No FF FF SF
// Fault FF FF SF
// Mesh SF SF SF
if (this->isGridVisualizationMode())
{
surfaceMode.setValueFromUi(SURFACE);
}
else
{
surfaceMode.setValueFromUi(FAULTS);
}
meshMode.setValueFromUi(FAULTS_MESH);
}
//--------------------------------------------------------------------------------------------------
@@ -1572,17 +1696,15 @@ void RimReservoirView::setMeshSurfDrawstyle()
//--------------------------------------------------------------------------------------------------
void RimReservoirView::setSurfOnlyDrawstyle()
{
if (surfaceMode == FAULTS || meshMode == FAULTS_MESH)
if (isGridVisualizationMode())
{
surfaceMode = FAULTS;
meshMode = NO_MESH;
surfaceMode.setValueFromUi(SURFACE);
}
else
{
surfaceMode = SURFACE;
meshMode = NO_MESH;
surfaceMode.setValueFromUi(FAULTS);
}
updateDisplayModelVisibility();
meshMode.setValueFromUi(NO_MESH);
}
//--------------------------------------------------------------------------------------------------
@@ -1592,15 +1714,30 @@ void RimReservoirView::setShowFaultsOnly(bool showFaults)
{
if (showFaults)
{
if (surfaceMode() != NO_SURFACE) surfaceMode = FAULTS;
if (meshMode() != NO_MESH) meshMode = FAULTS_MESH;
m_previousGridModeMeshLinesWasFaults = meshMode() == FAULTS_MESH;
if (surfaceMode() != NO_SURFACE) surfaceMode.setValueFromUi(FAULTS);
if (meshMode() != NO_MESH) meshMode.setValueFromUi(FAULTS_MESH);
}
else
{
if (surfaceMode() != NO_SURFACE) surfaceMode = SURFACE;
if (meshMode() != NO_MESH) meshMode = FULL_MESH;
if (surfaceMode() != NO_SURFACE) surfaceMode.setValueFromUi(SURFACE);
if (meshMode() != NO_MESH) meshMode.setValueFromUi(m_previousGridModeMeshLinesWasFaults ? FAULTS_MESH: FULL_MESH);
}
updateDisplayModelVisibility();
}
//--------------------------------------------------------------------------------------------------
///
// Surf: No Fault Surf
// Mesh -------------
// No F F G
// Fault F F G
// Mesh G G G
//
//--------------------------------------------------------------------------------------------------
bool RimReservoirView::isGridVisualizationMode() const
{
return ( this->surfaceMode() == SURFACE
|| this->meshMode() == FULL_MESH);
}
//--------------------------------------------------------------------------------------------------
@@ -1631,3 +1768,246 @@ void RimReservoirView::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering
cellGroup->add(&showInvalidCells);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimReservoirView::appendNNCResultInfo(size_t nncIndex, QString* resultInfo)
{
CVF_ASSERT(resultInfo);
if (m_reservoir && m_reservoir->reservoirData())
{
RigCaseData* eclipseCase = m_reservoir->reservoirData();
RigMainGrid* grid = eclipseCase->mainGrid();
CVF_ASSERT(grid);
RigNNCData* nncData = grid->nncData();
CVF_ASSERT(nncData);
if (nncData)
{
const RigConnection& conn = nncData->connections()[nncIndex];
cvf::StructGridInterface::FaceEnum face(conn.m_c1Face);
QString faultName;
resultInfo->append(QString("NNC Transmissibility : %1\n").arg(conn.m_transmissibility));
{
CVF_ASSERT(conn.m_c1GlobIdx < grid->cells().size());
const RigCell& cell = grid->cells()[conn.m_c1GlobIdx];
RigGridBase* hostGrid = cell.hostGrid();
size_t localCellIndex = cell.cellIndex();
size_t i, j, k;
if (hostGrid->ijkFromCellIndex(localCellIndex, &i, &j, &k))
{
// Adjust to 1-based Eclipse indexing
i++;
j++;
k++;
QString gridName = QString::fromStdString(hostGrid->gridName());
resultInfo->append(QString("NNC 1 : cell [%1, %2, %3] face %4 (%5)\n").arg(i).arg(j).arg(k).arg(face.text()).arg(gridName));
appendFaultName(hostGrid, conn.m_c1GlobIdx, conn.m_c1Face, &faultName);
}
}
{
CVF_ASSERT(conn.m_c2GlobIdx < grid->cells().size());
const RigCell& cell = grid->cells()[conn.m_c2GlobIdx];
RigGridBase* hostGrid = cell.hostGrid();
size_t localCellIndex = cell.cellIndex();
size_t i, j, k;
if (hostGrid->ijkFromCellIndex(localCellIndex, &i, &j, &k))
{
// Adjust to 1-based Eclipse indexing
i++;
j++;
k++;
QString gridName = QString::fromStdString(hostGrid->gridName());
cvf::StructGridInterface::FaceEnum oppositeFaceEnum(cvf::StructGridInterface::oppositeFace(face));
QString faceText = oppositeFaceEnum.text();
resultInfo->append(QString("NNC 2 : cell [%1, %2, %3] face %4 (%5)\n").arg(i).arg(j).arg(k).arg(faceText).arg(gridName));
if (faultName.isEmpty())
{
appendFaultName(hostGrid, conn.m_c2GlobIdx, cvf::StructGridInterface::oppositeFace(conn.m_c1Face), &faultName);
}
}
}
resultInfo->append(QString("Face: %2\n").arg(face.text()));
if (!faultName.isEmpty())
{
resultInfo->append(faultName);
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimReservoirView::updateFaultForcedVisibility()
{
// Force visibility of faults based on application state
// As fault geometry is visible in grid visualization mode, fault geometry must be forced visible
// even if the fault item is disabled in project tree view
caf::FixedArray<bool, RivReservoirViewPartMgr::PROPERTY_FILTERED> forceOn;
for (size_t i = 0; i < RivReservoirViewPartMgr::PROPERTY_FILTERED; i++)
{
forceOn[i] = false;
}
std::vector<RivReservoirViewPartMgr::ReservoirGeometryCacheType> faultParts = visibleFaultParts();
for (size_t i = 0; i < faultParts.size(); i++)
{
forceOn[faultParts[i]];
}
for (size_t i = 0; i < RivReservoirViewPartMgr::PROPERTY_FILTERED; i++)
{
RivReservoirViewPartMgr::ReservoirGeometryCacheType cacheType = (RivReservoirViewPartMgr::ReservoirGeometryCacheType)i;
m_reservoirGridPartManager->setFaultForceVisibilityForGeometryType(cacheType, forceOn[i]);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RivReservoirViewPartMgr::ReservoirGeometryCacheType> RimReservoirView::visibleFaultParts() const
{
std::vector<RivReservoirViewPartMgr::ReservoirGeometryCacheType> faultParts;
if (this->propertyFilterCollection()->hasActiveFilters() && !faultCollection()->showFaultsOutsideFilters)
{
faultParts.push_back(RivReservoirViewPartMgr::PROPERTY_FILTERED);
faultParts.push_back(RivReservoirViewPartMgr::PROPERTY_FILTERED_WELL_CELLS);
if (this->showInactiveCells())
{
faultParts.push_back(RivReservoirViewPartMgr::INACTIVE);
faultParts.push_back(RivReservoirViewPartMgr::RANGE_FILTERED_INACTIVE);
}
}
else if (this->faultCollection()->showFaultsOutsideFilters())
{
faultParts.push_back(RivReservoirViewPartMgr::ACTIVE);
faultParts.push_back(RivReservoirViewPartMgr::ALL_WELL_CELLS);
faultParts.push_back(RivReservoirViewPartMgr::RANGE_FILTERED);
faultParts.push_back(RivReservoirViewPartMgr::RANGE_FILTERED_WELL_CELLS);
faultParts.push_back(RivReservoirViewPartMgr::VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER);
faultParts.push_back(RivReservoirViewPartMgr::VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER);
if (this->showInactiveCells())
{
faultParts.push_back(RivReservoirViewPartMgr::INACTIVE);
faultParts.push_back(RivReservoirViewPartMgr::RANGE_FILTERED_INACTIVE);
}
}
else if (this->rangeFilterCollection()->hasActiveFilters() && this->wellCollection()->hasVisibleWellCells())
{
faultParts.push_back(RivReservoirViewPartMgr::RANGE_FILTERED);
faultParts.push_back(RivReservoirViewPartMgr::RANGE_FILTERED_WELL_CELLS);
faultParts.push_back(RivReservoirViewPartMgr::VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER);
faultParts.push_back(RivReservoirViewPartMgr::VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER);
if (this->showInactiveCells())
{
faultParts.push_back(RivReservoirViewPartMgr::RANGE_FILTERED_INACTIVE);
}
}
else if (!this->rangeFilterCollection()->hasActiveFilters() && this->wellCollection()->hasVisibleWellCells())
{
faultParts.push_back(RivReservoirViewPartMgr::VISIBLE_WELL_CELLS);
faultParts.push_back(RivReservoirViewPartMgr::VISIBLE_WELL_FENCE_CELLS);
}
else if (this->rangeFilterCollection()->hasActiveFilters() && !this->wellCollection()->hasVisibleWellCells())
{
faultParts.push_back(RivReservoirViewPartMgr::RANGE_FILTERED);
faultParts.push_back(RivReservoirViewPartMgr::RANGE_FILTERED_WELL_CELLS);
if (this->showInactiveCells())
{
faultParts.push_back(RivReservoirViewPartMgr::RANGE_FILTERED_INACTIVE);
}
}
else
{
faultParts.push_back(RivReservoirViewPartMgr::ACTIVE);
faultParts.push_back(RivReservoirViewPartMgr::ALL_WELL_CELLS);
if (this->showInactiveCells())
{
faultParts.push_back(RivReservoirViewPartMgr::INACTIVE);
faultParts.push_back(RivReservoirViewPartMgr::RANGE_FILTERED_INACTIVE);
}
}
return faultParts;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimReservoirView::updateFaultColors()
{
// Update all fault geometry
std::vector<RivReservoirViewPartMgr::ReservoirGeometryCacheType> faultGeometriesToRecolor = visibleFaultParts();
for (size_t i = 0; i < faultGeometriesToRecolor.size(); ++i)
{
m_reservoirGridPartManager->updateFaultColors(faultGeometriesToRecolor[i], m_currentTimeStep, this->cellResult());
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimReservoirView::appendFaultName(RigGridBase* grid, size_t cellIndex, cvf::StructGridInterface::FaceType face, QString* resultInfoText)
{
if (grid->isMainGrid())
{
RigMainGrid* mainGrid = grid->mainGrid();
for (size_t i = 0; i < mainGrid->faults().size(); i++)
{
const RigFault* rigFault = mainGrid->faults().at(i);
const std::vector<RigFault::FaultFace>& faultFaces = rigFault->faultFaces();
for (size_t fIdx = 0; fIdx < faultFaces.size(); fIdx++)
{
if (faultFaces[fIdx].m_nativeGlobalCellIndex == cellIndex)
{
if (face == faultFaces[fIdx].m_nativeFace )
{
resultInfoText->append(QString("Fault Name: %1\n").arg(rigFault->name()));
}
return;
}
if (faultFaces[fIdx].m_oppositeGlobalCellIndex == cellIndex)
{
if (face == cvf::StructGridInterface::oppositeFace(faultFaces[fIdx].m_nativeFace))
{
resultInfoText->append(QString("Fault Name: %1\n").arg(rigFault->name()));
}
return;
}
}
}
}
}

View File

@@ -30,6 +30,8 @@
#include <QPointer>
#include <QString>
#include "RimFaultCollection.h"
class RimCase;
class RimResultSlot;
class RimCellEdgeResultSlot;
@@ -49,6 +51,7 @@ class RiuViewer;
class RigGridBase;
class RigGridCellFaceVisibilityFilter;
class RimReservoirCellResultsStorage;
namespace cvf
{
class Transform;
@@ -56,14 +59,15 @@ namespace cvf
class ModelBasicList;
}
enum ViewState
enum PartRenderMaskEnum
{
GEOMETRY_ONLY,
STATIC_RESULT,
DYNAMIC_RESULT,
CELL_FACE_COMBINED_RESULT
surfaceBit = 0x00000001,
meshSurfaceBit = 0x00000002,
faultBit = 0x00000004,
meshFaultBit = 0x00000008,
};
//==================================================================================================
///
///
@@ -99,6 +103,8 @@ public:
caf::PdmField<RimWellCollection*> wellCollection;
caf::PdmField<RimFaultCollection*> faultCollection;
caf::PdmField<Rim3dOverlayInfoConfig*> overlayInfoConfig;
// Visualization setup fields
@@ -144,12 +150,16 @@ public:
void setMeshOnlyDrawstyle();
void setMeshSurfDrawstyle();
void setSurfOnlyDrawstyle();
void setFaultMeshSurfDrawstyle();
void setShowFaultsOnly(bool showFaults);
bool isGridVisualizationMode() const;
// Picking info
bool pickInfo(size_t gridIndex, size_t cellIndex, const cvf::Vec3d& point, QString* pickInfoText) const;
void appendCellResultInfo(size_t gridIndex, size_t cellIndex, QString* resultInfoText) ;
bool pickInfo(size_t gridIndex, size_t cellIndex, cvf::StructGridInterface::FaceType face, const cvf::Vec3d& point, QString* pickInfoText) const;
void appendCellResultInfo(size_t gridIndex, size_t cellIndex, cvf::StructGridInterface::FaceType face, QString* resultInfoText) ;
void appendNNCResultInfo(size_t nncIndex, QString* resultInfo);
// Does this belong here, really ?
void calculateVisibleWellCellsIncFence(cvf::UByteArray* visibleCells, RigGridBase * grid);
@@ -171,6 +181,8 @@ public:
// Display model generation
private:
void appendFaultName(RigGridBase* grid, size_t cellIndex, cvf::StructGridInterface::FaceType face, QString* resultInfoText);
void createDisplayModel();
void updateDisplayModelVisibility();
void updateCurrentTimeStep();
@@ -180,6 +192,11 @@ private:
void updateStaticCellColors(unsigned short geometryType);
void updateLegends();
std::vector<RivReservoirViewPartMgr::ReservoirGeometryCacheType> visibleFaultParts() const;
void updateFaultForcedVisibility();
void updateFaultColors();
cvf::ref<RivReservoirViewPartMgr> m_reservoirGridPartManager;
cvf::ref<RivReservoirPipesPartMgr> m_pipesPartManager;
@@ -198,12 +215,13 @@ private:
void syncronizeWellsWithResults();
void clampCurrentTimestep();
private:
caf::PdmField<int> m_currentTimeStep;
QPointer<RiuViewer> m_viewer;
caf::PdmPointer<RimCase> m_reservoir;
bool m_previousGridModeMeshLinesWasFaults;
std::vector<RivReservoirViewPartMgr::ReservoirGeometryCacheType> m_visibleGridParts;
};

View File

@@ -44,6 +44,7 @@
#include "Rim3dOverlayInfoConfig.h"
#include "RimOilField.h"
#include "RimAnalysisModels.h"
#include "RiaPreferences.h"
CAF_PDM_SOURCE_INIT(RimResultCase, "EclipseCase");
//--------------------------------------------------------------------------------------------------
@@ -97,13 +98,19 @@ bool RimResultCase::openEclipseGridFile()
return false;
}
cvf::ref<RigCaseData> eclipseCase = new RigCaseData;
RiaPreferences* prefs = RiaApplication::instance()->preferences();
readerInterface = new RifReaderEclipseOutput;
readerInterface->readFaultData(prefs->readFaultData());
readerInterface->setFilenamesWithFaults(this->filesContainingFaults());
cvf::ref<RigCaseData> eclipseCase = new RigCaseData;
if (!readerInterface->open(caseFileName(), eclipseCase.p()))
{
return false;
}
this->filesContainingFaults = readerInterface->filenamesWithFaults();
this->setReservoirData( eclipseCase.p() );
}
@@ -304,6 +311,16 @@ void RimResultCase::updateFilePathsFromProjectPath(const QString& newProjectPath
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimResultCase::setGridFileName(const QString& caseFileName)
{
this->caseFileName = caseFileName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@@ -40,6 +40,7 @@ public:
RimResultCase();
virtual ~RimResultCase();
void setGridFileName(const QString& caseFileName);
void setCaseInfo(const QString& userDescription, const QString& caseFileName);
virtual bool openEclipseGridFile();

View File

@@ -61,7 +61,7 @@ RimResultDefinition::RimResultDefinition()
CAF_PDM_InitFieldNoDefault(&m_porosityModelUiField, "MPorosityModelType", "Type", "", "", "");
m_porosityModelUiField.setIOReadable(false);
m_porosityModelUiField.setIOWritable(false);
CAF_PDM_InitField(&m_resultVariableUiField, "MResultVariable", RimDefines::undefinedResultName(), "Variable", "", "", "" );
CAF_PDM_InitField(&m_resultVariableUiField, "MResultVariable", RimDefines::undefinedResultName(), "Result property", "", "", "" );
m_resultVariableUiField.setIOReadable(false);
m_resultVariableUiField.setIOWritable(false);
@@ -158,12 +158,27 @@ QList<caf::PdmOptionItemInfo> RimResultDefinition::calculateValueOptions(const c
if (this->currentGridCellResults())
{
QStringList varList = getResultVariableListForCurrentUIFieldSettings();
bool hasCombinedTransmissibility = false;
QList<caf::PdmOptionItemInfo> optionList;
int i;
for (i = 0; i < varList.size(); ++i)
for (int i = 0; i < varList.size(); ++i)
{
optionList.push_back(caf::PdmOptionItemInfo( varList[i], varList[i]));
if (varList[i].compare(RimDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0)
{
hasCombinedTransmissibility = true;
continue;
}
optionList.push_back(caf::PdmOptionItemInfo(varList[i], varList[i]));
}
if (hasCombinedTransmissibility)
{
optionList.push_front(caf::PdmOptionItemInfo(RimDefines::combinedTransmissibilityResultName(), RimDefines::combinedTransmissibilityResultName()));
}
optionList.push_front(caf::PdmOptionItemInfo( RimDefines::undefinedResultName(), RimDefines::undefinedResultName() ));
if (useOptionsOnly) *useOptionsOnly = true;
@@ -196,7 +211,17 @@ void RimResultDefinition::loadResult()
RimReservoirCellResultsStorage* gridCellResults = this->currentGridCellResults();
if (gridCellResults)
{
gridCellResults->findOrLoadScalarResult(m_resultType(), m_resultVariable);
if (m_resultType() == RimDefines::STATIC_NATIVE &&
m_resultVariable().compare(RimDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0)
{
gridCellResults->findOrLoadScalarResult(m_resultType(), "TRANX");
gridCellResults->findOrLoadScalarResult(m_resultType(), "TRANY");
gridCellResults->findOrLoadScalarResult(m_resultType(), "TRANZ");
}
else
{
gridCellResults->findOrLoadScalarResult(m_resultType(), m_resultVariable);
}
}
}

View File

@@ -271,22 +271,21 @@ void RimStatisticsCase::computeStatistics()
RimStatisticsCaseEvaluator stat(sourceCases, timeStepIndices, statisticsConfig, resultCase);
stat.evaluateForResults(resultSpecification);
// Todo: Is this really the time and place to do the following ? JJS
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimStatisticsCase::scheduleACTIVEGeometryRegenOnReservoirViews()
{
for (size_t i = 0; i < reservoirViews().size(); i++)
{
RimReservoirView* reservoirView = reservoirViews()[i];
CVF_ASSERT(reservoirView);
reservoirView->scheduleGeometryRegen(RivReservoirViewPartMgr::ACTIVE);
reservoirView->createDisplayModelAndRedraw();
}
this->updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -462,6 +461,7 @@ void RimStatisticsCase::fieldChangedByUi(const caf::PdmFieldHandle* changedField
else
{
computeStatistics();
scheduleACTIVEGeometryRegenOnReservoirViews();
updateConnectedEditorsAndReservoirViews();
}
m_calculateEditCommand = false;

View File

@@ -53,6 +53,9 @@ public:
bool hasComputedStatistics() const;
void clearComputedStatistics();
void scheduleACTIVEGeometryRegenOnReservoirViews();
void updateConnectedEditorsAndReservoirViews();
virtual bool openEclipseGridFile();
RimCaseCollection* parentStatisticsCaseCollection();
@@ -77,7 +80,6 @@ private:
void updateSelectionSummaryLabel();
void updatePercentileUiVisibility();
void updateConnectedEditorsAndReservoirViews();
void setWellResultsAndUpdateViews(const cvf::Collection<RigSingleWellResultsData>& sourceCaseWellResults);
@@ -87,7 +89,6 @@ private:
virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue);
virtual void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute * attribute );
// Fields
caf::PdmField< caf::AppEnum< RimDefines::ResultCatType > > m_resultType;

View File

@@ -964,10 +964,16 @@ void RimUiTreeView::slotComputeStatistics()
statisticsCase->computeStatistics();
statisticsCase->scheduleACTIVEGeometryRegenOnReservoirViews();
statisticsCase->updateConnectedEditorsAndReservoirViews();
if (statisticsCase->reservoirViews.size() == 0)
{
slotAddView();
}
}
//--------------------------------------------------------------------------------------------------

View File

@@ -18,6 +18,10 @@ ${CEE_CURRENT_LIST_DIR}RigCaseCellResultsData.h
${CEE_CURRENT_LIST_DIR}RigSingleWellResultsData.h
${CEE_CURRENT_LIST_DIR}RigStatisticsMath.h
${CEE_CURRENT_LIST_DIR}RigWellPath.h
${CEE_CURRENT_LIST_DIR}RigFault.h
${CEE_CURRENT_LIST_DIR}RigNNCData.h
${CEE_CURRENT_LIST_DIR}cvfGeometryTools.h
${CEE_CURRENT_LIST_DIR}cvfGeometryTools.inl
)
set (SOURCE_GROUP_SOURCE_FILES
@@ -34,6 +38,9 @@ ${CEE_CURRENT_LIST_DIR}RigCaseCellResultsData.cpp
${CEE_CURRENT_LIST_DIR}RigSingleWellResultsData.cpp
${CEE_CURRENT_LIST_DIR}RigStatisticsMath.cpp
${CEE_CURRENT_LIST_DIR}RigWellPath.cpp
${CEE_CURRENT_LIST_DIR}RigFault.cpp
${CEE_CURRENT_LIST_DIR}RigNNCData.cpp
${CEE_CURRENT_LIST_DIR}cvfGeometryTools.cpp
)
list(APPEND CODE_HEADER_FILES

View File

@@ -39,6 +39,7 @@ set( UNIT_TEST_CPP_SOURCES
RigActiveCellInfo-Test.cpp
RigReservoir-Test.cpp
RigStatisticsMath-Test.cpp
cvfGeometryTools-Test.cpp
)
@@ -77,7 +78,6 @@ add_executable( ${ProjectName}
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set ( LINUX_LINK_LIBRARIES
lapack
pthread
)

View File

@@ -0,0 +1,517 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "gtest/gtest.h"
#include "cvfLibCore.h"
#include "cvfLibViewing.h"
#include "cvfLibRender.h"
#include "cvfLibGeometry.h"
#include "cafFixedArray.h"
#include "cvfArrayWrapperToEdit.h"
#include "cvfArrayWrapperConst.h"
#include "cvfGeometryTools.h"
#include "cvfBoundingBoxTree.h"
using namespace cvf;
#if 0
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ControlVolume::calculateCubeFaceStatus(const cvf::Vec3dArray& nodeCoords, double areaTolerance)
{
int cubeFace;
cvf::uint cubeFaceIndices[4];
for (cubeFace = 0; cubeFace < 6; ++cubeFace)
{
surfaceNodeIndices(static_cast<Defines::CubeFace>(cubeFace), cubeFaceIndices);
std::vector<const brv::Connection*> conns;
connections(static_cast<Defines::CubeFace>(cubeFace), &conns);
if (!conns.size())
{
m_cubeFaceStatus[cubeFace] = FREE_FACE;
}
else
{
double area = 0.5 * (nodeCoords[cubeFaceIndices[1]]-nodeCoords[cubeFaceIndices[0]] ^ nodeCoords[cubeFaceIndices[3]]-nodeCoords[cubeFaceIndices[0]]).length();
area += 0.5 * (nodeCoords[cubeFaceIndices[3]]-nodeCoords[cubeFaceIndices[2]] ^ nodeCoords[cubeFaceIndices[1]]-nodeCoords[cubeFaceIndices[2]]).length();
double totConnectionArea = 0;
size_t i;
for (i = 0; i < conns.size(); ++i)
{
totConnectionArea += conns[i]->brfArea();
}
if ( totConnectionArea < area - areaTolerance )
{
m_cubeFaceStatus[cubeFace] = PARTIALLY_COVERED;
}
else
{
m_cubeFaceStatus[cubeFace] = COMPLETELY_COVERED;
}
}
// Create a polygon to store the complete polygon of the faces
// not completely covered by connections
// This polygon will be filled with nodes later
if (m_cubeFaceStatus[cubeFace] != COMPLETELY_COVERED )
{
m_freeFacePolygons[cubeFace] = new std::list<std::pair<cvf::uint, bool> >;
}
}
}
#endif
template <typename NodeArrayType, typename NodeType, typename IndexType>
NodeType quadNormal (ArrayWrapperConst<NodeArrayType, NodeType> nodeCoords,
const IndexType cubeFaceIndices[4] )
{
return ( nodeCoords[cubeFaceIndices[2]] - nodeCoords[cubeFaceIndices[0]]) ^
( nodeCoords[cubeFaceIndices[3]] - nodeCoords[cubeFaceIndices[1]]);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
class QuadFaceIntersectorImplHandle
{
public:
virtual ~QuadFaceIntersectorImplHandle() {}
virtual bool intersect() = 0;
};
template < typename NodeArrayType, typename NodeType, typename IndicesArrayType, typename IndicesType>
class QuadFaceIntersectorImpl : public QuadFaceIntersectorImplHandle
{
public:
QuadFaceIntersectorImpl( ArrayWrapperToEdit<NodeArrayType, NodeType> nodeArray, ArrayWrapperToEdit<IndicesArrayType, IndicesType> indices)
: m_nodeArray(nodeArray),
m_indices(indices){}
virtual bool intersect()
{
size_t nodeCount = m_nodeArray.size();
NodeType a = m_nodeArray[0];
IndicesType idx = m_indices[0];
return true;
}
private:
ArrayWrapperToEdit<NodeArrayType, NodeType> m_nodeArray;
ArrayWrapperToEdit<IndicesArrayType, IndicesType> m_indices;
};
class QuadFaceIntersector
{
public:
template <typename NodeArrayType, typename NodeType, typename IndicesArrayType, typename IndicesType>
void setup( ArrayWrapperToEdit<NodeArrayType, NodeType> nodeArray, ArrayWrapperToEdit<IndicesArrayType, IndicesType> indices)
{
m_implementation = new QuadFaceIntersectorImpl< NodeArrayType, NodeType, IndicesArrayType, IndicesType>( nodeArray, indices);
}
bool intersect() { return m_implementation->intersect(); }
private:
QuadFaceIntersectorImplHandle * m_implementation;
};
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<cvf::Vec3d> createVertices()
{
std::vector<cvf::Vec3d> vxs;
vxs.resize(14, cvf::Vec3d::ZERO);
vxs[ 0]= cvf::Vec3d( 0 , 0 , 0 );
vxs[ 1]= cvf::Vec3d( 1 , 0 , 0 );
vxs[ 2]= cvf::Vec3d( 1 , 1 , 0 );
vxs[ 3]= cvf::Vec3d( 0 , 1 , 0 );
vxs[ 4]= cvf::Vec3d(-0.4 ,-0.2 , 0.0 );
vxs[ 5]= cvf::Vec3d( 0.4 , 0.6 , 0.0 );
vxs[ 6]= cvf::Vec3d( 0.8 , 0.2 , 0.0 );
vxs[ 7]= cvf::Vec3d( 0.0 ,-0.6 , 0.0 );
vxs[ 8]= cvf::Vec3d( 1.0 , 1.2 , 0.0 );
vxs[ 9]= cvf::Vec3d( 1.4 , 0.8 , 0.0 );
vxs[10]= cvf::Vec3d( 0.4 ,-0.2 , 0.0 );
vxs[11]= cvf::Vec3d( 1.2 , 0.6 , 0.0 );
vxs[12]= cvf::Vec3d( 1.6 , 0.2 , 0.0 );
vxs[13]= cvf::Vec3d( 0.8 ,-0.6 , 0.0 );
return vxs;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<caf::UintArray4> getCubeFaces()
{
std::vector<caf::UintArray4 > cubeFaces;
cvf::uint faces[4*4] = {
0, 1, 2, 3,
4, 5, 6, 7,
5, 8, 9, 6,
10, 11, 12, 13
};
cubeFaces.resize(4);
cubeFaces[0] = &faces[0];
cubeFaces[1] = &faces[4];
cubeFaces[2] = &faces[8];
cubeFaces[3] = &faces[12];
return cubeFaces;
}
std::ostream& operator<< (std::ostream& stream, std::vector<cvf::uint> v)
{
for (size_t i = 0; i < v.size(); ++i)
{
stream << v[i] << " ";
}
return stream;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST(CellFaceIntersectionTst, Intersection1)
{
std::vector<cvf::Vec3d> nodes = createVertices();
std::vector<cvf::Vec3d> additionalVertices;
std::vector< std::vector<cvf::uint> > overlapPolygons;
std::vector<caf::UintArray4> faces = getCubeFaces();
EdgeIntersectStorage<cvf::uint> edgeIntersectionStorage;
edgeIntersectionStorage.setVertexCount(nodes.size());
{
std::vector<cvf::uint> polygon;
bool isOk = false;
isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(
&polygon,
&additionalVertices,
&edgeIntersectionStorage,
wrapArrayConst(&nodes),
faces[0].data(),
faces[1].data(),
1e-6);
EXPECT_EQ( (size_t)5, polygon.size());
EXPECT_EQ( (size_t)2, additionalVertices.size());
EXPECT_TRUE(isOk);
overlapPolygons.push_back(polygon);
std::cout << polygon << std::endl;
}
{
std::vector<cvf::uint> polygon;
bool isOk = false;
isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(
&polygon,
&additionalVertices,
&edgeIntersectionStorage,
wrapArrayConst(&nodes),
faces[0].data(),
faces[2].data(),
1e-6);
EXPECT_EQ( (size_t)5, polygon.size());
EXPECT_EQ( (size_t)4, additionalVertices.size());
EXPECT_TRUE(isOk);
overlapPolygons.push_back(polygon);
std::cout << polygon << std::endl;
}
{
std::vector<cvf::uint> polygon;
bool isOk = false;
isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(
&polygon,
&additionalVertices,
&edgeIntersectionStorage,
wrapArrayConst(&nodes),
faces[0].data(),
faces[3].data(),
1e-6);
EXPECT_EQ( (size_t)3, polygon.size());
EXPECT_EQ( (size_t)6, additionalVertices.size());
EXPECT_TRUE(isOk);
overlapPolygons.push_back(polygon);
std::cout << polygon << std::endl;
}
nodes.insert(nodes.end(), additionalVertices.begin(), additionalVertices.end());
std::vector<cvf::uint> basePolygon;
basePolygon.insert(basePolygon.begin(), faces[0].data(), &(faces[0].data()[4]));
for (cvf::uint vxIdx = 0; vxIdx < nodes.size(); ++vxIdx)
{
bool inserted = GeometryTools::insertVertexInPolygon(
&basePolygon,
wrapArrayConst(&nodes),
vxIdx,
1e-6
);
}
EXPECT_EQ( (size_t)8, basePolygon.size());
std::cout << "Bp: " << basePolygon << std::endl;
for (size_t pIdx = 0; pIdx < overlapPolygons.size(); ++pIdx)
{
for (cvf::uint vxIdx = 0; vxIdx < nodes.size(); ++vxIdx)
{
bool inserted = GeometryTools::insertVertexInPolygon(
&overlapPolygons[pIdx],
wrapArrayConst(&nodes),
vxIdx,
1e-6
);
}
if (pIdx == 0)
{
EXPECT_EQ((size_t)5, overlapPolygons[pIdx].size());
}
if (pIdx == 1)
{
EXPECT_EQ((size_t)5, overlapPolygons[pIdx].size());
}
if (pIdx == 2)
{
EXPECT_EQ((size_t)4, overlapPolygons[pIdx].size());
}
std::cout << "Op" << pIdx << ":" << overlapPolygons[pIdx] << std::endl;
}
Vec3d normal = quadNormal(wrapArrayConst(&nodes), faces[0].data());
std::vector<bool> faceOverlapPolygonWindingSameAsCubeFaceFlags;
faceOverlapPolygonWindingSameAsCubeFaceFlags.resize(overlapPolygons.size(), true);
{
std::vector<cvf::uint> freeFacePolygon;
bool hasHoles = false;
std::vector< std::vector<cvf::uint>* > overlapPolygonPtrs;
for (size_t pIdx = 0; pIdx < overlapPolygons.size(); ++pIdx)
{
overlapPolygonPtrs.push_back(&(overlapPolygons[pIdx]));
}
GeometryTools::calculatePartiallyFreeCubeFacePolygon(
wrapArrayConst(&nodes),
wrapArrayConst(&basePolygon),
normal,
overlapPolygonPtrs,
faceOverlapPolygonWindingSameAsCubeFaceFlags,
&freeFacePolygon,
&hasHoles
);
EXPECT_EQ( (size_t)4, freeFacePolygon.size());
EXPECT_FALSE(hasHoles);
std::cout << "FF1: " << freeFacePolygon << std::endl;
}
{
std::vector<cvf::uint> freeFacePolygon;
bool hasHoles = false;
std::vector< std::vector<cvf::uint>* > overlapPolygonPtrs;
for (size_t pIdx = 0; pIdx < 1; ++pIdx)
{
overlapPolygonPtrs.push_back(&(overlapPolygons[pIdx]));
}
GeometryTools::calculatePartiallyFreeCubeFacePolygon(
wrapArrayConst(&nodes),
wrapArrayConst(&basePolygon),
normal,
overlapPolygonPtrs,
faceOverlapPolygonWindingSameAsCubeFaceFlags,
&freeFacePolygon,
&hasHoles
);
EXPECT_EQ( (size_t)9, freeFacePolygon.size());
EXPECT_FALSE(hasHoles);
std::cout << "FF2: " << freeFacePolygon << std::endl;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST(CellFaceIntersectionTst, Intersection)
{
std::vector<cvf::Vec3d> additionalVertices;
cvf::Vec3dArray nodes;
std::vector<size_t> polygon;
cvf::Array<size_t> ids;
size_t cv1CubeFaceIndices[4] = {0, 1, 2, 3};
size_t cv2CubeFaceIndices[4] = {4, 5, 6, 7};
nodes.resize(8);
nodes.setAll(cvf::Vec3d(0, 0, 0));
EdgeIntersectStorage<size_t> edgeIntersectionStorage;
edgeIntersectionStorage.setVertexCount(nodes.size());
// Face 1
nodes[0] = cvf::Vec3d(0, 0, 0);
nodes[1] = cvf::Vec3d(1, 0, 0);
nodes[2] = cvf::Vec3d(1, 1, 0);
nodes[3] = cvf::Vec3d(0, 1, 0);
// Face 2
nodes[4] = cvf::Vec3d(0, 0, 0);
nodes[5] = cvf::Vec3d(1, 0, 0);
nodes[6] = cvf::Vec3d(1, 1, 0);
nodes[7] = cvf::Vec3d(0, 1, 0);
bool isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, &additionalVertices, &edgeIntersectionStorage,
wrapArrayConst(&nodes), cv1CubeFaceIndices, cv2CubeFaceIndices, 1e-6);
EXPECT_EQ( (size_t)4, polygon.size());
EXPECT_EQ( (size_t)0, additionalVertices.size());
EXPECT_TRUE(isOk);
// Face 1
nodes[0] = cvf::Vec3d(0, 0, 0);
nodes[1] = cvf::Vec3d(1, 0, 0);
nodes[2] = cvf::Vec3d(1, 1, 0);
nodes[3] = cvf::Vec3d(0, 1, 0);
// Face 2
nodes[4] = cvf::Vec3d(0.5, -0.25, 0);
nodes[5] = cvf::Vec3d(1.25, 0.5, 0);
nodes[6] = cvf::Vec3d(0.5, 1.25, 0);
nodes[7] = cvf::Vec3d(-0.25, 0.5, 0);
polygon.clear();
isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, &additionalVertices, &edgeIntersectionStorage,
wrapArrayConst(&nodes), cv1CubeFaceIndices, cv2CubeFaceIndices, 1e-6);
EXPECT_EQ( (size_t)8, polygon.size());
EXPECT_EQ( (size_t)8, additionalVertices.size());
EXPECT_TRUE(isOk);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST(CellFaceIntersectionTst, FreeFacePolygon)
{
std::vector<cvf::Vec3d> additionalVertices;
cvf::Vec3dArray nodes;
std::vector<size_t> polygon;
cvf::Array<size_t> ids;
size_t cv1CubeFaceIndices[4] = {0, 1, 2, 3};
size_t cv2CubeFaceIndices[4] = {4, 5, 6, 7};
nodes.resize(8);
nodes.setAll(cvf::Vec3d(0, 0, 0));
EdgeIntersectStorage<size_t> edgeIntersectionStorage;
edgeIntersectionStorage.setVertexCount(nodes.size());
// Face 1
nodes[0] = cvf::Vec3d(0, 0, 0);
nodes[1] = cvf::Vec3d(1, 0, 0);
nodes[2] = cvf::Vec3d(1, 1, 0);
nodes[3] = cvf::Vec3d(0, 1, 0);
// Face 2
nodes[4] = cvf::Vec3d(0, 0, 0);
nodes[5] = cvf::Vec3d(1, 0, 0);
nodes[6] = cvf::Vec3d(1, 1, 0);
nodes[7] = cvf::Vec3d(0, 1, 0);
bool isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, &additionalVertices, &edgeIntersectionStorage,
wrapArrayConst(&nodes), cv1CubeFaceIndices, cv2CubeFaceIndices, 1e-6);
EXPECT_EQ( (size_t)4, polygon.size());
EXPECT_EQ( (size_t)0, additionalVertices.size());
EXPECT_TRUE(isOk);
std::vector< bool > faceOverlapPolygonWinding;
std::vector< std::vector<size_t>* > faceOverlapPolygons;
faceOverlapPolygons.push_back(&polygon);
faceOverlapPolygonWinding.push_back(true);
std::vector<size_t> partialFacePolygon;
bool hasHoles = false;
GeometryTools::calculatePartiallyFreeCubeFacePolygon(
wrapArrayConst(&nodes),
wrapArrayConst(cv1CubeFaceIndices, 4),
Vec3d(0,0,1),
faceOverlapPolygons,
faceOverlapPolygonWinding,
&partialFacePolygon,
&hasHoles);
// Face 1
nodes[0] = cvf::Vec3d(0, 0, 0);
nodes[1] = cvf::Vec3d(1, 0, 0);
nodes[2] = cvf::Vec3d(1, 1, 0);
nodes[3] = cvf::Vec3d(0, 1, 0);
// Face 2
nodes[4] = cvf::Vec3d(0.5, -0.25, 0);
nodes[5] = cvf::Vec3d(1.25, 0.5, 0);
nodes[6] = cvf::Vec3d(0.5, 1.25, 0);
nodes[7] = cvf::Vec3d(-0.25, 0.5, 0);
polygon.clear();
isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, &additionalVertices, &edgeIntersectionStorage,
wrapArrayConst(&nodes), cv1CubeFaceIndices, cv2CubeFaceIndices, 1e-6);
EXPECT_EQ( (size_t)8, polygon.size());
EXPECT_EQ( (size_t)8, additionalVertices.size());
EXPECT_TRUE(isOk);
}

View File

@@ -33,6 +33,8 @@ RigCaseCellResultsData::RigCaseCellResultsData(RigMainGrid* ownerGrid)
{
CVF_ASSERT(ownerGrid != NULL);
m_ownerMainGrid = ownerGrid;
m_combinedTransmissibilityResultIndex = cvf::UNDEFINED_SIZE_T;
}
@@ -115,6 +117,18 @@ void RigCaseCellResultsData::minMaxCellScalarValues(size_t scalarResultIndex, si
return;
}
if (scalarResultIndex == m_combinedTransmissibilityResultIndex)
{
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);
return;
}
std::vector<double>& values = m_cellScalarResults[scalarResultIndex][timeStepIndex];
size_t i;
@@ -167,12 +181,28 @@ const std::vector<size_t>& RigCaseCellResultsData::cellScalarValuesHistogram(siz
this->minMaxCellScalarValues( scalarResultIndex, min, max );
RigHistogramCalculator histCalc(min, max, nBins, &m_histograms[scalarResultIndex]);
for (size_t tsIdx = 0; tsIdx < this->timeStepCount(scalarResultIndex); tsIdx++)
if (scalarResultIndex == m_combinedTransmissibilityResultIndex)
{
std::vector<double>& values = m_cellScalarResults[scalarResultIndex][tsIdx];
size_t tranX, tranY, tranZ;
if (findTransmissibilityResults(tranX, tranY, tranZ))
{
for (size_t tsIdx = 0; tsIdx < this->timeStepCount(scalarResultIndex); tsIdx++)
{
histCalc.addData(m_cellScalarResults[tranX][tsIdx]);
histCalc.addData(m_cellScalarResults[tranY][tsIdx]);
histCalc.addData(m_cellScalarResults[tranZ][tsIdx]);
}
}
}
else
{
for (size_t tsIdx = 0; tsIdx < this->timeStepCount(scalarResultIndex); tsIdx++)
{
std::vector<double>& values = m_cellScalarResults[scalarResultIndex][tsIdx];
histCalc.addData(values);
}
histCalc.addData(values);
}
}
m_p10p90[scalarResultIndex].first = histCalc.calculatePercentil(0.1);
m_p10p90[scalarResultIndex].second = histCalc.calculatePercentil(0.9);
@@ -215,14 +245,52 @@ void RigCaseCellResultsData::meanCellScalarValues(size_t scalarResultIndex, doub
double valueSum = 0.0;
size_t count = 0;
for (size_t tIdx = 0; tIdx < timeStepCount(scalarResultIndex); tIdx++)
if (scalarResultIndex == m_combinedTransmissibilityResultIndex)
{
std::vector<double>& values = m_cellScalarResults[scalarResultIndex][tIdx];
for (size_t cIdx = 0; cIdx < values.size(); ++cIdx)
size_t tranX, tranY, tranZ;
if (findTransmissibilityResults(tranX, tranY, tranZ))
{
valueSum += values[cIdx];
for (size_t tIdx = 0; tIdx < timeStepCount(tranX); tIdx++)
{
{
std::vector<double>& values = m_cellScalarResults[tranX][tIdx];
for (size_t cIdx = 0; cIdx < values.size(); ++cIdx)
{
valueSum += values[cIdx];
}
count += values.size();
}
{
std::vector<double>& values = m_cellScalarResults[tranY][tIdx];
for (size_t cIdx = 0; cIdx < values.size(); ++cIdx)
{
valueSum += values[cIdx];
}
count += values.size();
}
{
std::vector<double>& values = m_cellScalarResults[tranZ][tIdx];
for (size_t cIdx = 0; cIdx < values.size(); ++cIdx)
{
valueSum += values[cIdx];
}
count += values.size();
}
}
}
}
else
{
for (size_t tIdx = 0; tIdx < timeStepCount(scalarResultIndex); tIdx++)
{
std::vector<double>& values = m_cellScalarResults[scalarResultIndex][tIdx];
for (size_t cIdx = 0; cIdx < values.size(); ++cIdx)
{
valueSum += values[cIdx];
}
count += values.size();
}
count += values.size();
}
m_meanValues[scalarResultIndex] = valueSum/count;
@@ -665,6 +733,19 @@ void RigCaseCellResultsData::posNegClosestToZero(size_t scalarResultIndex, size_
return;
}
if (scalarResultIndex == m_combinedTransmissibilityResultIndex)
{
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);
}
return;
}
std::vector<double>& values = m_cellScalarResults[scalarResultIndex][timeStepIndex];
size_t i;
@@ -690,3 +771,37 @@ void RigCaseCellResultsData::posNegClosestToZero(size_t scalarResultIndex, size_
m_posNegClosestToZeroPrTs[scalarResultIndex][timeStepIndex].second= neg;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigCaseCellResultsData::createCombinedTransmissibilityResult()
{
size_t combinedTransmissibilityIndex = findScalarResultIndex(RimDefines::STATIC_NATIVE, RimDefines::combinedTransmissibilityResultName());
if (combinedTransmissibilityIndex != cvf::UNDEFINED_SIZE_T) return;
size_t tranX, tranY, tranZ;
if (!findTransmissibilityResults(tranX, tranY, tranZ)) return;
m_combinedTransmissibilityResultIndex = addStaticScalarResult(RimDefines::STATIC_NATIVE, RimDefines::combinedTransmissibilityResultName(), false, 0);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigCaseCellResultsData::findTransmissibilityResults(size_t& tranX, size_t& tranY, size_t& tranZ) const
{
tranX = findScalarResultIndex(RimDefines::STATIC_NATIVE, "TRANX");
tranY = findScalarResultIndex(RimDefines::STATIC_NATIVE, "TRANY");
tranZ = findScalarResultIndex(RimDefines::STATIC_NATIVE, "TRANZ");
if (tranX == cvf::UNDEFINED_SIZE_T ||
tranY == cvf::UNDEFINED_SIZE_T ||
tranZ == cvf::UNDEFINED_SIZE_T)
{
return false;
}
return true;
}

View File

@@ -66,6 +66,8 @@ public:
size_t addEmptyScalarResult(RimDefines::ResultCatType type, const QString& resultName, bool needsToBeStored);
QString makeResultNameUnique(const QString& resultNameProposal) const;
void createCombinedTransmissibilityResult();
void removeResult(const QString& resultName);
void clearAllResults();
void freeAllocatedResultsData();
@@ -107,6 +109,8 @@ public:
bool needsToBeStored,
size_t resultValueCount);
bool findTransmissibilityResults(size_t& tranX, size_t& tranY, size_t& tranZ) const;
private:
std::vector< std::vector< std::vector<double> > > m_cellScalarResults; ///< Scalar results on the complete reservoir for each Result index (ResultVariable) and timestep
std::vector< std::pair<double, double> > m_maxMinValues; ///< Max min values for each Result index
@@ -118,7 +122,7 @@ private:
std::vector< std::vector< std::pair<double, double> > > m_maxMinValuesPrTs; ///< Max min values for each Result index and timestep
std::vector< std::vector< std::pair<double, double> > > m_posNegClosestToZeroPrTs;
size_t m_combinedTransmissibilityResultIndex;
private:
std::vector<ResultInfo> m_resultInfos;

View File

@@ -44,7 +44,7 @@ RigCell::RigCell() :
m_cellIndex(cvf::UNDEFINED_SIZE_T),
m_coarseningBoxIndex(cvf::UNDEFINED_SIZE_T)
{
memcpy(m_cornerIndices.m_array, undefinedCornersArray, 8*sizeof(size_t));
memcpy(m_cornerIndices.data(), undefinedCornersArray, 8*sizeof(size_t));
m_cellFaceFaults[0] = false;
m_cellFaceFaults[1] = false;
@@ -229,10 +229,12 @@ cvf::Vec3d RigCell::faceCenter(cvf::StructGridInterface::FaceType face) const
cvf::ubyte faceVertexIndices[4];
cvf::StructGridInterface::cellFaceVertexIndices(face, faceVertexIndices);
const std::vector<cvf::Vec3d>& nodeCoords = m_hostGrid->mainGrid()->nodes();
size_t i;
for (i = 0; i < 4; i++)
{
avg += m_hostGrid->mainGrid()->nodes()[m_cornerIndices[faceVertexIndices[i]]];
avg += nodeCoords[m_cornerIndices[faceVertexIndices[i]]];
}
avg /= 4.0;
@@ -240,6 +242,19 @@ cvf::Vec3d RigCell::faceCenter(cvf::StructGridInterface::FaceType face) const
return avg;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Vec3d RigCell::faceNormal(cvf::StructGridInterface::FaceType face) const
{
cvf::ubyte faceVertexIndices[4];
cvf::StructGridInterface::cellFaceVertexIndices(face, faceVertexIndices);
const std::vector<cvf::Vec3d>& nodeCoords = m_hostGrid->mainGrid()->nodes();
return ( nodeCoords[m_cornerIndices[faceVertexIndices[2]]] - nodeCoords[m_cornerIndices[faceVertexIndices[0]]]) ^
( nodeCoords[m_cornerIndices[faceVertexIndices[3]]] - nodeCoords[m_cornerIndices[faceVertexIndices[1]]]);
}
//--------------------------------------------------------------------------------------------------
/// Find the intersection between the cell and the ray. The point closest to the ray origin is returned
/// in \a intersectionPoint, while the return value is the total number of intersections with the 24 triangles
@@ -291,3 +306,17 @@ int RigCell::firstIntersectionPoint(const cvf::Ray& ray, cvf::Vec3d* intersectio
return intersectionCount;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigCell::faceIndices(cvf::StructGridInterface::FaceType face, caf::SizeTArray4* indices) const
{
cvf::ubyte faceVertexIndices[4];
cvf::StructGridInterface::cellFaceVertexIndices(face, faceVertexIndices);
(*indices)[0] = m_cornerIndices[faceVertexIndices[0]];
(*indices)[1] = m_cornerIndices[faceVertexIndices[1]];
(*indices)[2] = m_cornerIndices[faceVertexIndices[2]];
(*indices)[3] = m_cornerIndices[faceVertexIndices[3]];
}

View File

@@ -36,6 +36,7 @@ public:
caf::SizeTArray8& cornerIndices() { return m_cornerIndices;}
const caf::SizeTArray8& cornerIndices() const { return m_cornerIndices;}
void faceIndices(cvf::StructGridInterface::FaceType face, caf::SizeTArray4 * faceIndices) const ;
bool isInvalid() const { return m_isInvalid; }
void setInvalid( bool val ) { m_isInvalid = val; }
@@ -62,6 +63,8 @@ public:
cvf::Vec3d center() const;
cvf::Vec3d faceCenter(cvf::StructGridInterface::FaceType face) const;
cvf::Vec3d faceNormal(cvf::StructGridInterface::FaceType face) const;
int firstIntersectionPoint(const cvf::Ray& ray, cvf::Vec3d* intersectionPoint) const;
bool isLongPyramidCell(double maxHeightFactor = 5, double nodeNearTolerance = 1e-3 ) const;
private:

View File

@@ -0,0 +1,154 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RigFault.h"
#include "RigMainGrid.h"
cvf::ref<RigFaultsPrCellAccumulator> RigFault::m_faultsPrCellAcc;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigFault::RigFault()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigFault::addCellRangeForFace(cvf::StructGridInterface::FaceType face, const cvf::CellRange& cellRange)
{
size_t faceIndex = static_cast<size_t>(face);
CVF_ASSERT(faceIndex < 6);
m_cellRangesForFaces[faceIndex].push_back(cellRange);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigFault::setName(const QString& name)
{
m_name = name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RigFault::name() const
{
return m_name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RigFault::FaultFace>& RigFault::faultFaces()
{
return m_faultFaces;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<RigFault::FaultFace>& RigFault::faultFaces() const
{
return m_faultFaces;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigFault::computeFaultFacesFromCellRanges(const RigMainGrid* mainGrid)
{
if (!mainGrid) return;
m_faultFaces.clear();
for (size_t faceType = 0; faceType < 6; faceType++)
{
cvf::StructGridInterface::FaceType faceEnum = cvf::StructGridInterface::FaceType(faceType);
const std::vector<cvf::CellRange>& cellRanges = m_cellRangesForFaces[faceType];
for (size_t i = 0; i < cellRanges.size(); i++)
{
const cvf::CellRange& cellRange = cellRanges[i];
cvf::Vec3st min, max;
cellRange.range(min, max);
for (size_t i = min.x(); i <= max.x(); i++)
{
if (i >= mainGrid->cellCountI())
{
continue;
}
for (size_t j = min.y(); j <= max.y(); j++)
{
if (j >= mainGrid->cellCountJ())
{
continue;
}
for (size_t k = min.z(); k <= max.z(); k++)
{
if (k >= mainGrid->cellCountK())
{
continue;
}
// Do not need to compute global grid cell index as for a maingrid localIndex == globalIndex
//size_t globalCellIndex = grid->globalGridCellIndex(localCellIndex);
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)
{
size_t localCellIndex = mainGrid->cellIndexFromIJK(i, j, k);
size_t oppositeCellIndex = mainGrid->cellIndexFromIJK(ni, nj, nk);
m_faultFaces.push_back(FaultFace(localCellIndex, faceEnum, oppositeCellIndex));
}
else
{
//cvf::Trace::show("Warning: Undefined Fault neighbor detected.");
}
}
}
}
}
}
}
void RigFault::accumulateFaultsPrCell(RigFaultsPrCellAccumulator* faultsPrCellAcc, int faultIdx)
{
for (size_t ffIdx = 0; ffIdx < m_faultFaces.size(); ++ffIdx)
{
const FaultFace& ff = m_faultFaces[ffIdx];
// Could detect overlapping faults here .... if (faultsPrCellAcc->faultIdx(ff.m_nativeGlobalCellIndex, ff.m_nativeFace) >= 0)
faultsPrCellAcc->setFaultIdx(ff.m_nativeGlobalCellIndex, ff.m_nativeFace, faultIdx);
faultsPrCellAcc->setFaultIdx(ff.m_oppositeGlobalCellIndex, cvf::StructGridInterface::oppositeFace(ff.m_nativeFace), faultIdx);
}
}

View File

@@ -0,0 +1,109 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfBase.h"
#include "cvfObject.h"
#include "cvfVector3.h"
#include "cvfBoundingBox.h"
#include <vector>
#include <QString>
#include "cvfStructGrid.h"
#include "cvfCellRange.h"
#include "cafFixedArray.h"
class RigMainGrid;
class RigFaultsPrCellAccumulator : public cvf::Object
{
public:
enum { NO_FAULT = -1, UNKNOWN_FAULT = -2 };
public:
RigFaultsPrCellAccumulator(size_t globalCellCount)
{
const int initVals[6] = { NO_FAULT, NO_FAULT, NO_FAULT, NO_FAULT, NO_FAULT, NO_FAULT};
caf::IntArray6 initVal;
initVal = initVals;
m_faultIdxForCellFace.resize(globalCellCount, initVal);
}
inline int faultIdx(size_t globalCellIdx, cvf::StructGridInterface::FaceType face)
{
return m_faultIdxForCellFace[globalCellIdx][face];
}
inline void setFaultIdx(size_t globalCellIdx, cvf::StructGridInterface::FaceType face, int faultIdx)
{
m_faultIdxForCellFace[globalCellIdx][face] = faultIdx;
}
private:
std::vector< caf::IntArray6 > m_faultIdxForCellFace;
};
class RigFault : public cvf::Object
{
public:
struct FaultFace
{
FaultFace(size_t nativeGlobalCellIndex, cvf::StructGridInterface::FaceType nativeFace, size_t oppositeGlobalCellIndex) :
m_nativeGlobalCellIndex(nativeGlobalCellIndex),
m_nativeFace(nativeFace),
m_oppositeGlobalCellIndex(oppositeGlobalCellIndex)
{ }
size_t m_nativeGlobalCellIndex;
cvf::StructGridInterface::FaceType m_nativeFace;
size_t m_oppositeGlobalCellIndex;
};
public:
RigFault();
void setName(const QString& name);
QString name() const;
void addCellRangeForFace(cvf::StructGridInterface::FaceType face, const cvf::CellRange& cellRange);
void computeFaultFacesFromCellRanges(const RigMainGrid* grid);
void accumulateFaultsPrCell(RigFaultsPrCellAccumulator* faultsPrCellAcc, int faultIdx);
std::vector<FaultFace>& faultFaces();
const std::vector<FaultFace>& faultFaces() const;
std::vector<size_t>& connectionIndices() { return m_connectionIndices; }
const std::vector<size_t>& connectionIndices() const { return m_connectionIndices; }
static RigFaultsPrCellAccumulator* faultsPrCellAccumulator() { CVF_ASSERT(m_faultsPrCellAcc.notNull()); return m_faultsPrCellAcc.p();}
static void initFaultsPrCellAccumulator(size_t globalCellCount) { m_faultsPrCellAcc = new RigFaultsPrCellAccumulator(globalCellCount); }
private:
QString m_name;
caf::FixedArray<std::vector<cvf::CellRange>, 6> m_cellRangesForFaces;
std::vector<FaultFace> m_faultFaces;
std::vector<size_t> m_connectionIndices;
static cvf::ref<RigFaultsPrCellAccumulator> m_faultsPrCellAcc;
};

View File

@@ -307,7 +307,7 @@ bool RigGridBase::isCellValid(size_t i, size_t j, size_t k) const
//--------------------------------------------------------------------------------------------------
/// TODO: Use structgrid::neighborIJKAtCellFace
///
//--------------------------------------------------------------------------------------------------
bool RigGridBase::cellIJKNeighbor(size_t i, size_t j, size_t k, FaceType face, size_t* neighborCellIndex) const
{
@@ -327,94 +327,6 @@ bool RigGridBase::cellIJKNeighbor(size_t i, size_t j, size_t k, FaceType face, s
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigGridBase::computeFaults()
{
//size_t k;
#pragma omp parallel for
for (int k = 0; k < static_cast<int>(cellCountK()); k++)
{
size_t j;
for (j = 0; j < cellCountJ(); j++)
{
size_t i;
for (i = 0; i < cellCountI(); i++)
{
size_t idx = cellIndexFromIJK(i, j, k);
RigCell& currentCell = cell(idx);
if (currentCell.isInvalid())
{
continue;
}
size_t faceIdx;
for (faceIdx = 0; faceIdx < 6; faceIdx++)
{
cvf::StructGridInterface::FaceType face = static_cast<cvf::StructGridInterface::FaceType>(faceIdx);
size_t cellNeighbourIdx = 0;
if (!cellIJKNeighbor(i, j, k, face, &cellNeighbourIdx))
{
continue;
}
const RigCell& neighbourCell = cell(cellNeighbourIdx);
if (neighbourCell.isInvalid())
{
continue;
}
cvf::Vec3d currentCellFaceVertices[4];
{
cvf::ubyte faceVertexIndices[4];
cellFaceVertexIndices(face, faceVertexIndices);
const caf::SizeTArray8& cornerIndices = currentCell.cornerIndices();
currentCellFaceVertices[0].set(m_mainGrid->nodes()[cornerIndices[faceVertexIndices[0]]]);
currentCellFaceVertices[1].set(m_mainGrid->nodes()[cornerIndices[faceVertexIndices[1]]]);
currentCellFaceVertices[2].set(m_mainGrid->nodes()[cornerIndices[faceVertexIndices[2]]]);
currentCellFaceVertices[3].set(m_mainGrid->nodes()[cornerIndices[faceVertexIndices[3]]]);
}
cvf::Vec3d neighbourCellFaceVertices[4];
{
cvf::ubyte faceVertexIndices[4];
StructGridInterface::FaceType opposite = StructGridInterface::oppositeFace(face);
cellFaceVertexIndices(opposite, faceVertexIndices);
const caf::SizeTArray8& cornerIndices = neighbourCell.cornerIndices();
neighbourCellFaceVertices[0].set(m_mainGrid->nodes()[cornerIndices[faceVertexIndices[0]]]);
neighbourCellFaceVertices[1].set(m_mainGrid->nodes()[cornerIndices[faceVertexIndices[3]]]);
neighbourCellFaceVertices[2].set(m_mainGrid->nodes()[cornerIndices[faceVertexIndices[2]]]);
neighbourCellFaceVertices[3].set(m_mainGrid->nodes()[cornerIndices[faceVertexIndices[1]]]);
}
bool sharedFaceVertices = true;
// Check if vertices are matching
double tolerance = 1e-6;
for (size_t cellFaceIdx = 0; cellFaceIdx < 4; cellFaceIdx++)
{
if (currentCellFaceVertices[cellFaceIdx].pointDistance(neighbourCellFaceVertices[cellFaceIdx]) > tolerance )
{
sharedFaceVertices = false;
}
}
if (!sharedFaceVertices)
{
currentCell.setCellFaceFault(face);
}
}
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -545,49 +457,51 @@ bool RigGridCellFaceVisibilityFilter::isFaceVisible(size_t i, size_t j, size_t k
{
CVF_TIGHT_ASSERT(m_grid);
if (m_showFaultFaces)
size_t cellIndex = m_grid->cellIndexFromIJK(i, j, k);
if (m_grid->cell(cellIndex).subGrid())
{
size_t cellIndex = m_grid->cellIndexFromIJK(i, j, k);
if (m_grid->cell(cellIndex).isCellFaceFault(face))
{
return true;
}
// Do not show any faces in the place where a LGR is present
return false;
}
if (m_showExternalFaces)
size_t ni, nj, nk;
cvf::StructGridInterface::neighborIJKAtCellFace(i, j, k, face, &ni, &nj, &nk);
// If the cell is on the edge of the grid, Interpret as having an invisible neighbour
if (ni >= m_grid->cellCountI() || nj >= m_grid->cellCountJ() || nk >= m_grid->cellCountK())
{
size_t cellIndex = m_grid->cellIndexFromIJK(i, j, k);
if (m_grid->cell(cellIndex).subGrid())
{
// Do not show any faces in the place where a LGR is present
return false;
}
size_t ni, nj, nk;
cvf::StructGridInterface::neighborIJKAtCellFace(i, j, k, face, &ni, &nj, &nk);
// If the cell is on the edge of the grid, Interpret as having an invisible neighbour
if (ni >= m_grid->cellCountI() || nj >= m_grid->cellCountJ() || nk >= m_grid->cellCountK())
{
return true;
}
return true;
}
size_t neighborCellIndex = m_grid->cellIndexFromIJK(ni, nj, nk);
size_t neighborCellIndex = m_grid->cellIndexFromIJK(ni, nj, nk);
// Do show the faces in the boarder between this grid and a possible LGR. Some of the LGR cells
// might not be visible.
if (m_grid->cell(neighborCellIndex).subGrid())
{
return true;
}
// Do show the faces in the boarder between this grid and a possible LGR. Some of the LGR cells
// might not be visible.
if (m_grid->cell(neighborCellIndex).subGrid())
{
return true;
}
// If the neighbour cell is invisible, we need to draw the face
if ((cellVisibility != NULL) && !(*cellVisibility)[neighborCellIndex])
{
return true;
}
// If the neighbour cell is invisible, we need to draw the face
if ((cellVisibility != NULL) && !(*cellVisibility)[neighborCellIndex])
{
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigFaultFaceVisibilityFilter::isFaceVisible(size_t i, size_t j, size_t k, cvf::StructGridInterface::FaceType face, const cvf::UByteArray* cellVisibility) const
{
size_t cellIndex = m_grid->cellIndexFromIJK(i, j, k);
if (m_grid->cell(cellIndex).isCellFaceFault(face))
{
return true;
}
return false;
}

View File

@@ -22,15 +22,17 @@
#include "cvfVector3.h"
#include "cvfBoundingBox.h"
#include "cvfStructGrid.h"
#include "cvfStructGridGeometryGenerator.h"
#include "cvfStructGridScalarDataAccess.h"
#include "cafFixedArray.h"
#include <vector>
#include <string>
#include "cvfStructGridScalarDataAccess.h"
#include "RifReaderInterface.h"
#include "cafFixedArray.h"
#include "RigFault.h"
class RigMainGrid;
@@ -65,7 +67,6 @@ public:
std::string gridName() const;
void setGridName(const std::string& gridName);
void computeFaults();
bool isMainGrid() const;
RigMainGrid* mainGrid() const { return m_mainGrid; }
@@ -75,6 +76,7 @@ public:
void coarseningBox(size_t coarseningBoxIndex, size_t* i1, size_t* i2, size_t* j1, size_t* j2, size_t* k1, size_t* k2) const;
cvf::BoundingBox boundingBox();
protected:
friend class RigMainGrid;//::initAllSubGridsParentGridPointer();
@@ -116,6 +118,7 @@ private:
cvf::BoundingBox m_boundingBox;
std::vector<caf::SizeTArray6> m_coarseningBoxInfo;
};
@@ -123,17 +126,25 @@ class RigGridCellFaceVisibilityFilter : public cvf::CellFaceVisibilityFilter
{
public:
RigGridCellFaceVisibilityFilter(const RigGridBase* grid)
: m_grid(grid),
m_showFaultFaces(true),
m_showExternalFaces(true)
: m_grid(grid)
{
}
virtual bool isFaceVisible( size_t i, size_t j, size_t k, cvf::StructGridInterface::FaceType face, const cvf::UByteArray* cellVisibility ) const;
private:
const RigGridBase* m_grid;
};
class RigFaultFaceVisibilityFilter : public cvf::CellFaceVisibilityFilter
{
public:
bool m_showFaultFaces;
bool m_showExternalFaces;
RigFaultFaceVisibilityFilter(const RigGridBase* grid)
: m_grid(grid)
{
}
virtual bool isFaceVisible( size_t i, size_t j, size_t k, cvf::StructGridInterface::FaceType face, const cvf::UByteArray* cellVisibility ) const;
private:
const RigGridBase* m_grid;

View File

@@ -19,6 +19,7 @@
#include "RigMainGrid.h"
#include "cvfAssert.h"
#include "RimDefines.h"
RigMainGrid::RigMainGrid(void)
: RigGridBase(this)
@@ -179,3 +180,189 @@ RigGridBase* RigMainGrid::gridById(int localGridId)
return this->gridByIndex(m_gridIdToIndexMapping[localGridId]);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigNNCData* RigMainGrid::nncData()
{
if (m_nncData.isNull())
{
m_nncData = new RigNNCData;
}
return m_nncData.p();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigMainGrid::setFaults(const cvf::Collection<RigFault>& faults)
{
m_faults = faults;
#pragma omp parallel for
for (int i = 0; i < static_cast<int>(m_faults.size()); i++)
{
m_faults[i]->computeFaultFacesFromCellRanges(this->mainGrid());
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigMainGrid::calculateFaults()
{
//RigFault::initFaultsPrCellAccumulator(m_cells.size());
cvf::ref<RigFaultsPrCellAccumulator> faultsPrCellAcc = new RigFaultsPrCellAccumulator(m_cells.size());
// Spread fault idx'es on the cells from the faults
for (size_t fIdx = 0 ; fIdx < m_faults.size(); ++fIdx)
{
m_faults[fIdx]->accumulateFaultsPrCell(faultsPrCellAcc.p(), static_cast<int>(fIdx));
}
// Find the geometrical faults that is in addition
RigFault * unNamedFault = new RigFault;
int unNamedFaultIdx = static_cast<int>(m_faults.size());
for (size_t gcIdx = 0 ; gcIdx < m_cells.size(); ++gcIdx)
{
if ( m_cells[gcIdx].isInvalid())
{
continue;
}
size_t neighborGlobalCellIdx;
size_t neighborGridCellIdx;
size_t i, j, k;
RigGridBase* hostGrid = NULL;
bool firstNO_FAULTFaceForCell = true;
for (char faceIdx = 0; faceIdx < 6; ++faceIdx)
{
cvf::StructGridInterface::FaceType face = cvf::StructGridInterface::FaceType(faceIdx);
if (faultsPrCellAcc->faultIdx(gcIdx, face) == RigFaultsPrCellAccumulator::NO_FAULT)
{
// Find neighbor cell
if (firstNO_FAULTFaceForCell) // To avoid doing this for every face, and only when detecting a NO_FAULT
{
hostGrid = m_cells[gcIdx].hostGrid();
hostGrid->ijkFromCellIndex(m_cells[gcIdx].cellIndex(), &i,&j, &k);
firstNO_FAULTFaceForCell = false;
}
if(!hostGrid->cellIJKNeighbor(i, j, k, face, &neighborGridCellIdx))
{
continue;
}
neighborGlobalCellIdx = hostGrid->globalGridCellIndex(neighborGridCellIdx);
if (m_cells[neighborGlobalCellIdx].isInvalid())
{
continue;
}
double tolerance = 1e-6;
caf::SizeTArray4 faceIdxs;
m_cells[gcIdx].faceIndices(face, &faceIdxs);
caf::SizeTArray4 nbFaceIdxs;
m_cells[neighborGlobalCellIdx].faceIndices(StructGridInterface::oppositeFace(face), &nbFaceIdxs);
const std::vector<cvf::Vec3d>& vxs = m_mainGrid->nodes();
bool sharedFaceVertices = true;
if (sharedFaceVertices && vxs[faceIdxs[0]].pointDistance(vxs[nbFaceIdxs[0]]) > tolerance ) sharedFaceVertices = false;
if (sharedFaceVertices && vxs[faceIdxs[1]].pointDistance(vxs[nbFaceIdxs[3]]) > tolerance ) sharedFaceVertices = false;
if (sharedFaceVertices && vxs[faceIdxs[2]].pointDistance(vxs[nbFaceIdxs[2]]) > tolerance ) sharedFaceVertices = false;
if (sharedFaceVertices && vxs[faceIdxs[3]].pointDistance(vxs[nbFaceIdxs[1]]) > tolerance ) sharedFaceVertices = false;
if (sharedFaceVertices)
{
continue;
}
// To avoid doing this calculation for the opposite face
faultsPrCellAcc->setFaultIdx(gcIdx, face, unNamedFaultIdx);
faultsPrCellAcc->setFaultIdx(neighborGlobalCellIdx, StructGridInterface::oppositeFace(face), unNamedFaultIdx);
//m_cells[gcIdx].setCellFaceFault(face);
//m_cells[neighborGlobalCellIdx].setCellFaceFault(StructGridInterface::oppositeFace(face));
// Add as fault face only if the grid index is less than the neighbors
if (gcIdx < neighborGlobalCellIdx)
{
RigFault::FaultFace ff(gcIdx, cvf::StructGridInterface::FaceType(faceIdx), neighborGlobalCellIdx);
unNamedFault->faultFaces().push_back(ff);
}
else
{
CVF_FAIL_MSG("Found fault with global neighbor index less than the native index. "); // Should never occur. because we flag the opposite face in the faultsPrCellAcc
}
}
}
}
if (unNamedFault->faultFaces().size())
{
unNamedFault->setName(RimDefines::undefinedGridFaultName());
m_faults.push_back(unNamedFault);
}
// Distribute nnc's to the faults
const std::vector<RigConnection>& nncs = this->nncData()->connections();
for (size_t nncIdx = 0; nncIdx < nncs.size(); ++nncIdx)
{
// Find the fault for each side of the nnc
const RigConnection& conn = nncs[nncIdx];
int fIdx1 = RigFaultsPrCellAccumulator::NO_FAULT;
int fIdx2 = RigFaultsPrCellAccumulator::NO_FAULT;
if (conn.m_c1Face != StructGridInterface::NO_FACE)
{
fIdx1 = faultsPrCellAcc->faultIdx(conn.m_c1GlobIdx, conn.m_c1Face);
fIdx2 = faultsPrCellAcc->faultIdx(conn.m_c2GlobIdx, StructGridInterface::oppositeFace(conn.m_c1Face));
}
if (fIdx1 < 0 && fIdx2 < 0)
{
cvf::String lgrString ("Same Grid");
if (m_cells[conn.m_c1GlobIdx].hostGrid() != m_cells[conn.m_c2GlobIdx].hostGrid() )
{
lgrString = "Different Grid";
}
//cvf::Trace::show("NNC: No Fault for NNC C1: " + cvf::String((int)conn.m_c1GlobIdx) + " C2: " + cvf::String((int)conn.m_c2GlobIdx) + " Grid: " + lgrString);
}
if (fIdx1 >= 0)
{
// Add the connection to both, if they are different.
m_faults[fIdx1]->connectionIndices().push_back(nncIdx);
}
if (fIdx2 != fIdx1)
{
if (fIdx2 >= 0)
{
m_faults[fIdx2]->connectionIndices().push_back(nncIdx);
}
}
}
}
//--------------------------------------------------------------------------------------------------
/// The cell is normally inverted due to Depth becoming -Z at import,
/// but if (only) one of the flipX/Y is done, the cell is back to nomal
//--------------------------------------------------------------------------------------------------
bool RigMainGrid::faceNormalsIsOutwards() const
{
return m_flipXAxis ^ m_flipYAxis;
}

View File

@@ -26,6 +26,7 @@
#include "RifReaderInterface.h"
#include <QtGlobal>
#include "RigNNCData.h"
class RigMainGrid : public RigGridBase
{
@@ -46,6 +47,12 @@ public:
const RigGridBase* gridByIndex(size_t localGridIndex) const;
RigGridBase* gridById(int localGridId);
RigNNCData* nncData();
void setFaults(const cvf::Collection<RigFault>& faults);
const cvf::Collection<RigFault>& faults() { return m_faults; }
void calculateFaults();
bool faceNormalsIsOutwards() const;
void computeCachedData();
// Overrides
@@ -65,6 +72,10 @@ private:
cvf::Collection<RigLocalGrid> m_localGrids; ///< List of all the LGR's in this reservoir
std::vector<size_t> m_gridIdToIndexMapping; ///< Mapping from LGR Id to index.
cvf::Collection<RigFault> m_faults;
cvf::ref<RigNNCData> m_nncData;
cvf::Vec3d m_displayModelOffset;
bool m_flipXAxis;

View File

@@ -0,0 +1,180 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RigNNCData.h"
#include "RigMainGrid.h"
#include "cvfGeometryTools.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigNNCData::RigNNCData()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigNNCData::processConnections(const RigMainGrid& mainGrid)
{
//cvf::Trace::show("NNC: Total number: " + cvf::String((int)m_connections.size()));
for (size_t cnIdx = 0; cnIdx < m_connections.size(); ++cnIdx)
{
const RigCell& c1 = mainGrid.cells()[m_connections[cnIdx].m_c1GlobIdx];
const RigCell& c2 = mainGrid.cells()[m_connections[cnIdx].m_c2GlobIdx];
// Try to find the shared face
char hasNeighbourInAnyDirection = 0;
bool isPossibleNeighborInDirection[6]= {true, true, true, true, true, true};
if (c1.hostGrid() == c2.hostGrid())
{
size_t i1, j1, k1;
c1.hostGrid()->ijkFromCellIndex(c1.cellIndex(), &i1, &j1, &k1);
size_t i2, j2, k2;
c2.hostGrid()->ijkFromCellIndex(c2.cellIndex(), &i2, &j2, &k2);
isPossibleNeighborInDirection[cvf::StructGridInterface::POS_I] = ((i1 + 1) == i2);
isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_I] = ((i2 + 1) == i1);
isPossibleNeighborInDirection[cvf::StructGridInterface::POS_J] = ((j1 + 1) == j2);
isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_J] = ((j2 + 1) == j1);
isPossibleNeighborInDirection[cvf::StructGridInterface::POS_K] = ((k1 + 1) == k2);
isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_K] = ((k2 + 1) == k1);
hasNeighbourInAnyDirection =
isPossibleNeighborInDirection[cvf::StructGridInterface::POS_I]
+ isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_I]
+ isPossibleNeighborInDirection[cvf::StructGridInterface::POS_J]
+ isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_J]
+ isPossibleNeighborInDirection[cvf::StructGridInterface::POS_K]
+ isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_K];
// If cell 2 is not adjancent with respect to any of the six ijk directions,
// assume that we have no overlapping area.
if (!hasNeighbourInAnyDirection)
{
// Add to search map
//m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c1GlobIdx][cvf::StructGridInterface::NO_FACE].push_back(cnIdx);
//m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c2GlobIdx][cvf::StructGridInterface::NO_FACE].push_back(cnIdx);
//cvf::Trace::show("NNC: No direct neighbors : C1: " + cvf::String((int)m_connections[cnIdx].m_c1GlobIdx) + " C2: " + cvf::String((int)m_connections[cnIdx].m_c2GlobIdx));
continue; // to next connection
}
}
// Possibly do some testing to avoid unneccesary overlap calculations
cvf::Vec3d normal;
for (char fIdx = 0; fIdx < 6; ++fIdx)
{
if (isPossibleNeighborInDirection[fIdx])
{
cvf::Vec3d fc1 = c1.faceCenter((cvf::StructGridInterface::FaceType)(fIdx));
cvf::Vec3d fc2 = c2.faceCenter(cvf::StructGridInterface::oppositeFace((cvf::StructGridInterface::FaceType)(fIdx)));
cvf::Vec3d fc1ToFc2 = fc2 - fc1;
normal = c1.faceNormal((cvf::StructGridInterface::FaceType)(fIdx));
normal.normalize();
// Check that face centers are approx in the face plane
if (normal.dot(fc1ToFc2) < 0.01*fc1ToFc2.length())
{
}
}
}
bool foundAnyOverlap = false;
for (char fIdx = 0; fIdx < 6; ++fIdx)
{
if (!isPossibleNeighborInDirection[fIdx])
{
continue;
}
// Calculate connection polygon
std::vector<size_t> polygon;
std::vector<cvf::Vec3d> intersections;
caf::SizeTArray4 face1;
caf::SizeTArray4 face2;
c1.faceIndices((cvf::StructGridInterface::FaceType)(fIdx), &face1);
c2.faceIndices(cvf::StructGridInterface::oppositeFace((cvf::StructGridInterface::FaceType)(fIdx)), &face2);
bool foundOverlap = cvf::GeometryTools::calculateOverlapPolygonOfTwoQuads(
&polygon,
&intersections,
(cvf::EdgeIntersectStorage<size_t>*)NULL,
cvf::wrapArrayConst(&mainGrid.nodes()),
face1.data(),
face2.data(),
1e-6);
if (foundOverlap)
{
foundAnyOverlap = true;
// Found an overlap polygon. Store data about connection
m_connections[cnIdx].m_c1Face = (cvf::StructGridInterface::FaceType)fIdx;
for (size_t pIdx = 0; pIdx < polygon.size(); ++pIdx)
{
if (polygon[pIdx] < mainGrid.nodes().size())
m_connections[cnIdx].m_polygon.push_back(mainGrid.nodes()[polygon[pIdx]]);
else
m_connections[cnIdx].m_polygon.push_back(intersections[polygon[pIdx] - mainGrid.nodes().size()]);
}
// Add to search map, possibly not needed
//m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c1GlobIdx][fIdx].push_back(cnIdx);
//m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c2GlobIdx][cvf::StructGridInterface::oppositeFace((cvf::StructGridInterface::FaceType)(fIdx))].push_back(cnIdx);
break; // The connection face is found. Stop looping over the cell faces. Jump to next connection
}
}
if (!foundAnyOverlap)
{
//cvf::Trace::show("NNC: No overlap found for : C1: " + cvf::String((int)m_connections[cnIdx].m_c1GlobIdx) + "C2: " + cvf::String((int)m_connections[cnIdx].m_c2GlobIdx));
}
}
}
/*
//--------------------------------------------------------------------------------------------------
/// TODO: Possibly not needed !
//--------------------------------------------------------------------------------------------------
const std::vector<size_t>& RigNNCData::findConnectionIndices( size_t globalCellIndex, cvf::StructGridInterface::FaceType face) const
{
ConnectionSearchMap::const_iterator it;
static std::vector<size_t> empty;
it = m_cellIdxToFaceToConnectionIdxMap.find(globalCellIndex);
if (it != m_cellIdxToFaceToConnectionIdxMap.end())
{
return it->second[face];
}
return empty;
}
*/

View File

@@ -0,0 +1,72 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfBase.h"
#include "cvfObject.h"
#include "cvfVector3.h"
#include <vector>
#include "cvfStructGrid.h"
#include "cafFixedArray.h"
class RigMainGrid;
class RigConnection
{
public:
RigConnection( )
: m_c1GlobIdx(cvf::UNDEFINED_SIZE_T),
m_c1Face(cvf::StructGridInterface::NO_FACE),
m_c2GlobIdx(cvf::UNDEFINED_SIZE_T),
m_transmissibility(0.0)
{}
size_t m_c1GlobIdx;
cvf::StructGridInterface::FaceType m_c1Face;
size_t m_c2GlobIdx;
double m_transmissibility;
std::vector<cvf::Vec3d> m_polygon;
};
class RigNNCData : public cvf::Object
{
public:
RigNNCData();
void processConnections(const RigMainGrid& mainGrid);
std::vector<RigConnection>& connections() { return m_connections; }
const std::vector<RigConnection>& connections() const { return m_connections; };
private: // This section is possibly not needed
//const std::vector<size_t>& findConnectionIndices(size_t globalCellIndex, cvf::StructGridInterface::FaceType face) const;
//typedef std::map<size_t, caf::FixedArray<std::vector<size_t>, 7 > > ConnectionSearchMap;
//ConnectionSearchMap m_cellIdxToFaceToConnectionIdxMap;
private:
std::vector<RigConnection> m_connections;
};

View File

@@ -248,6 +248,8 @@ void RigReservoirBuilderMock::populateReservoir(RigCaseData* eclipseCase)
addWellData(eclipseCase, eclipseCase->mainGrid());
addFaults(eclipseCase);
// Set all cells active
RigActiveCellInfo* activeCellInfo = eclipseCase->activeCellInfo(RifReaderInterface::MATRIX_RESULTS);
activeCellInfo->setGlobalCellCount(eclipseCase->mainGrid()->cells().size());
@@ -479,3 +481,43 @@ void RigReservoirBuilderMock::addWellData(RigCaseData* eclipseCase, RigGridBase*
eclipseCase->setWellResults(wells);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigReservoirBuilderMock::addFaults(RigCaseData* eclipseCase)
{
if (!eclipseCase) return;
RigMainGrid* grid = eclipseCase->mainGrid();
if (!grid) return;
cvf::Collection<RigFault> faults;
{
cvf::ref<RigFault> fault = new RigFault;
fault->setName("Fault A");
cvf::Vec3st min = cvf::Vec3st::ZERO;
cvf::Vec3st max(0, 0, cellDimension().z() - 2);
if (cellDimension().x() > 5)
{
min.x() = cellDimension().x() / 2;
max.x() = min.x() + 1;
}
if (cellDimension().y() > 5)
{
min.y() = cellDimension().y() / 2;
max.y() = cellDimension().y() / 2;
}
cvf::CellRange cellRange(min, max);
fault->addCellRangeForFace(cvf::StructGridInterface::POS_I, cellRange);
faults.push_back(fault.p());
}
grid->setFaults(faults);
}

View File

@@ -62,6 +62,7 @@ public:
bool dynamicResult(RigCaseData* eclipseCase, const QString& result, size_t stepIndex, std::vector<double>* values );
private:
void addFaults(RigCaseData* eclipseCase);
void addWellData(RigCaseData* eclipseCase, RigGridBase* grid);
static void appendCells(size_t nodeStartIndex, size_t cellCount, RigGridBase* hostGrid, std::vector<RigCell>& cells);

View File

@@ -0,0 +1,925 @@
#include "cvfGeometryTools.h"
#pragma warning (disable : 4503)
namespace cvf
{
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Vec3d GeometryTools::computeFaceCenter(const cvf::Vec3d& v0, const cvf::Vec3d& v1, const cvf::Vec3d& v2, const cvf::Vec3d& v3)
{
cvf::Vec3d centerCoord = v0;
centerCoord += v1;
centerCoord += v2;
centerCoord += v3;
centerCoord *= 0.25;
return centerCoord;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int GeometryTools::findClosestAxis(const cvf::Vec3d& vec )
{
int closestAxis = 0;
double maxComponent = fabs(vec.x());
if (fabs(vec.y()) > maxComponent)
{
maxComponent = (float)fabs(vec.y());
closestAxis = 1;
}
if (fabs(vec.z()) > maxComponent)
{
closestAxis = 2;
}
return closestAxis;
}
//--------------------------------------------------------------------------------------------------
/// Return angle between vectors if v1 x v2 is same way as normal
/// else return 2PI - angle
/// This means if the angle is slightly "negative", using the right hand rule, this method will return
/// nearly 2*PI
//--------------------------------------------------------------------------------------------------
double const MY_PI = 4 * atan(1.0);
double GeometryTools::getAngle(const cvf::Vec3d& positiveNormalAxis, const cvf::Vec3d& v1, const cvf::Vec3d& v2)
{
bool isOk = false;
cvf::Vec3d v1N = v1.getNormalized(&isOk);
if (!isOk) return 0;
cvf::Vec3d v2N = v2.getNormalized();
if (!isOk) return 0;
double cosAng = v1N * v2N;
// Guard acos against out-of-domain input
if (cosAng <= -1.0)
{
cosAng = -1.0;
}
else if (cosAng >= 1.0)
{
cosAng = 1.0;
}
double angle = acos(cosAng);
cvf::Vec3d crossProd = v1N ^ v2N;
double sign = positiveNormalAxis * crossProd;
if (sign < 0)
{
angle = 2*MY_PI - angle;
}
return angle;
}
//--------------------------------------------------------------------------------------------------
/// Return angle in radians between vectors [0, Pi]
/// If v1 or v2 is zero, the method will return 0.
//--------------------------------------------------------------------------------------------------
double GeometryTools::getAngle(const cvf::Vec3d& v1, const cvf::Vec3d& v2)
{
bool isOk = false;
cvf::Vec3d v1N = v1.getNormalized(&isOk);
if (!isOk) return 0;
cvf::Vec3d v2N = v2.getNormalized();
if (!isOk) return 0;
double cosAng = v1N * v2N;
// Guard acos against out-of-domain input
if (cosAng <= -1.0)
{
cosAng = -1.0;
}
else if (cosAng >= 1.0)
{
cosAng = 1.0;
}
double angle = acos(cosAng);
return angle;
}
/*
Determine the intersection point of two line segments
From Paul Bourke, but modified to really handle coincident lines
and lines with touching vertexes.
Returns an intersection status telling what kind of intersection it is (if any)
*/
GeometryTools::IntersectionStatus inPlaneLineIntersect(
double x1, double y1,
double x2, double y2,
double x3, double y3,
double x4, double y4,
double l1NormalizedTolerance, double l2NormalizedTolerance,
double *x, double *y, double* fractionAlongLine1, double* fractionAlongLine2)
{
double mua, mub;
double denom, numera, numerb;
denom = (y4-y3) * (x2-x1) - (x4-x3) * (y2-y1);
numera = (x4-x3) * (y1-y3) - (y4-y3) * (x1-x3);
numerb = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3);
double EPS = 1e-40;
// Are the line coincident?
if (fabs(numera) < EPS && fabs(numerb) < EPS && fabs(denom) < EPS)
{
#if 0
*x = 0;
*y = 0;
*fractionAlongLine1 = 0;
*fractionAlongLine2 = 0;
return GeometryTools::LINES_OVERLAP;
#else
cvf::Vec3d p12(x2-x1, y2-y1, 0);
cvf::Vec3d p13(x3-x1, y3-y1, 0);
cvf::Vec3d p34(x4-x3, y4-y3, 0);
double length12 = p12.length();
double length34 = p34.length();
// Check if the p1 p2 line is a point
if (length12 < EPS )
{
cvf::Vec3d p34(x4-x3, y4-y3, 0);
*x = x1;
*y = y1;
*fractionAlongLine1 = 1;
*fractionAlongLine2 = p13.length()/p34.length();
return GeometryTools::LINES_OVERLAP;
}
cvf::Vec3d p14(x4-x1, y4-y1, 0);
cvf::Vec3d p32(x2-x3, y2-y3, 0);
cvf::Vec3d e12 = p12.getNormalized();
double normDist13 = e12*p13 / length12;
double normDist14 = e12*p14 / length12;
// Check if both points on the p3 p4 line is outside line p1 p2.
if( (normDist13 < 0 - l1NormalizedTolerance && normDist14 < 0-l1NormalizedTolerance )|| (normDist13 > 1 +l1NormalizedTolerance && normDist14 > 1+l1NormalizedTolerance ) )
{
*x = 0;
*y = 0;
*fractionAlongLine1 = 0;
*fractionAlongLine2 = 0;
return GeometryTools::NO_INTERSECTION;
}
double normDist32 = e12*p32 / length34;
double normDist31 = -e12*p13 / length34;
// Set up fractions along lines to the edge2 vertex actually touching edge 1.
/// if two, select the one furthest from the start
bool pt3IsInside = false;
bool pt4IsInside = false;
if ((0.0 - l1NormalizedTolerance) <= normDist13 && normDist13 <= (1.0 +l1NormalizedTolerance) ) pt3IsInside = true;
if ((0.0 - l1NormalizedTolerance) <= normDist14 && normDist14 <= (1.0 +l1NormalizedTolerance) ) pt4IsInside = true;
if (pt3IsInside && !pt4IsInside)
{
*fractionAlongLine1 = normDist13;
*fractionAlongLine2 = 0.0;
*x = x3;
*y = y3;
}
else if (pt4IsInside && !pt3IsInside)
{
*fractionAlongLine1 = normDist14;
*fractionAlongLine2 = 1.0;
*x = x4;
*y = y4;
}
else if (pt3IsInside && pt4IsInside)
{
// Return edge 2 vertex furthest along edge 1
if (normDist13 <= normDist14)
{
*fractionAlongLine1 = normDist14 ;
*fractionAlongLine2 = 1.0;
*x = x4;
*y = y4;
}
else
{
*fractionAlongLine1 = normDist13;
*fractionAlongLine2 = 0.0;
*x = x3;
*y = y3;
}
}
else // both outside on each side
{
// Return End of edge 1
*fractionAlongLine1 = 1.0;
*fractionAlongLine2 = normDist32;
*x = x2;
*y = y2;
}
return GeometryTools::LINES_OVERLAP;
#endif
}
/* Are the line parallel */
if (fabs(denom) < EPS) {
*x = 0;
*y = 0;
*fractionAlongLine1 = 0;
*fractionAlongLine2 = 0;
return GeometryTools::NO_INTERSECTION;
}
/* Is the intersection along the the segments */
mua = numera / denom;
mub = numerb / denom;
*x = x1 + mua * (x2 - x1);
*y = y1 + mua * (y2 - y1);
*fractionAlongLine1 = mua;
*fractionAlongLine2 = mub;
if (mua < 0 - l1NormalizedTolerance || 1 + l1NormalizedTolerance < mua || mub < 0 - l2NormalizedTolerance || 1 + l2NormalizedTolerance < mub)
{
return GeometryTools::LINES_INTERSECT_OUTSIDE;
}
else if (fabs(mua) < l1NormalizedTolerance || fabs(1-mua) < l1NormalizedTolerance ||
fabs(mub) < l2NormalizedTolerance || fabs(1-mub) < l2NormalizedTolerance )
{
if (fabs(mua) < l1NormalizedTolerance) *fractionAlongLine1 = 0;
if (fabs(1-mua) < l1NormalizedTolerance) *fractionAlongLine1 = 1;
if (fabs(mub) < l2NormalizedTolerance) *fractionAlongLine2 = 0;
if (fabs(1-mub) < l2NormalizedTolerance) *fractionAlongLine2 = 1;
return GeometryTools::LINES_TOUCH;
}
else
{
return GeometryTools::LINES_CROSSES;
}
}
//----------------------------------------------------------------------------------------------------------
/// Supposed to find the intersection point if lines intersect
/// It returns the intersection status telling if the lines only touch or are overlapping
//----------------------------------------------------------------------------------------------------------
GeometryTools::IntersectionStatus
GeometryTools::inPlaneLineIntersect3D( const cvf::Vec3d& planeNormal,
const cvf::Vec3d& p1, const cvf::Vec3d& p2, const cvf::Vec3d& p3, const cvf::Vec3d& p4,
cvf::Vec3d* intersectionPoint, double* fractionAlongLine1, double* fractionAlongLine2, double tolerance)
{
CVF_ASSERT (intersectionPoint != NULL);
int Z = findClosestAxis(planeNormal);
int X = (Z + 1) % 3;
int Y = (Z + 2) % 3;
double x, y;
// Todo: handle zero length edges
double l1NormTol = tolerance / (p2-p1).length();
double l2NormTol = tolerance / (p4-p3).length();
IntersectionStatus intersectionStatus = inPlaneLineIntersect(p1[X], p1[Y], p2[X], p2[Y], p3[X], p3[Y], p4[X], p4[Y], l1NormTol, l2NormTol, &x, &y, fractionAlongLine1, fractionAlongLine2);
// Check if we have a valid intersection point
if (intersectionStatus == NO_INTERSECTION || intersectionStatus == LINES_OVERLAP)
{
intersectionPoint->setZero();
}
else
{
*intersectionPoint = p1 + (*fractionAlongLine1)*(p2-p1);
}
return intersectionStatus;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double GeometryTools::linePointSquareDist(const cvf::Vec3d& p1, const cvf::Vec3d& p2, const cvf::Vec3d& p3)
{
cvf::Vec3d v31 = p3 - p1;
cvf::Vec3d v21 = p2 - p1;
double geomTolerance = 1e-24;
if (v21.lengthSquared() < geomTolerance)
{
// P2 and P1 coincide, use distance from P3 to P1
return v31.lengthSquared();
}
double u = (v31*v21)/(v21*v21);
cvf::Vec3d pOnLine(0,0,0);
if (0 < u && u < 1) pOnLine = p1 + u*v21;
else if (u <= 0 ) pOnLine = p1;
else pOnLine = p2;
return (p3-pOnLine).lengthSquared();
}
//--------------------------------------------------------------------------------------------------
// Copyright 2001, softSurfer (www.softsurfer.com)
// This code may be freely used and modified for any purpose
// providing that this copyright notice is included with it.
// SoftSurfer makes no warranty for this code, and cannot be held
// liable for any real or imagined damage resulting from its use.
// Users of this code must verify correctness for their application.
// http://www.softsurfer.com/Archive/algorithm_0105/algorithm_0105.htm
//
/// Intersect a line segment with a 3D triangle
/// Input: A line segment p0, p1. A triangle t0, t1, t2.
/// Output: *intersectionPoint = intersection point (when it exists)
/// Return: -1 = triangle is degenerate (a segment or point)
/// 0 = disjoint (no intersect)
/// 1 = intersect in unique point I1
/// 2 = are in the same plane
//--------------------------------------------------------------------------------------------------
#define SMALL_NUM 0.00000001 // anything that avoids division overflow
// dot product (3D) which allows vector operations in arguments
#define dot(u,v) ((u).x() * (v).x() + (u).y() * (v).y() + (u).z() * (v).z())
int GeometryTools::intersectLineSegmentTriangle( const cvf::Vec3d p0, const cvf::Vec3d p1,
const cvf::Vec3d t0, const cvf::Vec3d t1, const cvf::Vec3d t2,
cvf::Vec3d* intersectionPoint )
{
CVF_ASSERT(intersectionPoint != NULL);
cvf::Vec3d u, v, n; // triangle vectors
cvf::Vec3d dir, w0, w; // ray vectors
double r, a, b; // params to calc ray-plane intersect
// get triangle edge vectors and plane normal
u = t1 - t0;
v = t2 - t0;
n = u ^ v; // cross product
if (n == cvf::Vec3d::ZERO) // triangle is degenerate
return -1; // do not deal with this case
dir = p1 - p0; // ray direction vector
w0 = p0 - t0;
a = -dot(n, w0);
b = dot(n, dir);
if (fabs(b) < SMALL_NUM) { // ray is parallel to triangle plane
if (a == 0) // ray lies in triangle plane
return 2;
else return 0; // ray disjoint from plane
}
// get intersect point of ray with triangle plane
r = a / b;
if (r < 0.0) // ray goes away from triangle
return 0; // => no intersect
if (r > 1.0) // Line segment does not reach triangle
return 0;
*intersectionPoint = p0 + r * dir; // intersect point of ray and plane
// is I inside T?
double uu, uv, vv, wu, wv, D;
uu = dot(u, u);
uv = dot(u, v);
vv = dot(v, v);
w = *intersectionPoint - t0;
wu = dot(w, u);
wv = dot(w, v);
D = uv * uv - uu * vv;
// get and test parametric coords
double s, t;
s = (uv * wv - vv * wu) / D;
if (s < 0.0 || s > 1.0) // I is outside T
return 0;
t = (uv * wu - uu * wv) / D;
if (t < 0.0 || (s + t) > 1.0) // I is outside T
return 0;
return 1; // I is in T
}
/*
// t0 = (x0, y0, z0)
// t1 = (x1, y1, z1)
// t2 = (x2, y2, z2)
//
// p = (xp, yp, zp)
cvf::Vec3d barycentricCoordsExperiment(const cvf::Vec3d& t0, const cvf::Vec3d& t1, const cvf::Vec3d& t2, const cvf::Vec3d& p)
{
det = x0(y1*z2 - y2*z1) + x1(y2*z0 - z2*y0) + x2(y0*z1 - y1*z0);
b0 = ((x1 * y2 - x2*y1)*zp + xp*(y1*z2-y2*z1) + yp*(x2*z1-x1*z2)) / det;
b1 = ((x2 * y0 - x0*y2)*zp + xp*(y2*z0-y0*z2) + yp*(x0*z2-x2*z0)) / det;
b2 = ((x0 * y1 - x1*y0)*zp + xp*(y0*z1-y1*z0) + yp*(x1*z0-x0*z1)) / det;
}
*/
inline double TriArea2D(double x1, double y1, double x2, double y2, double x3, double y3)
{
return (x1-x2)*(y2-y3) - (x2-x3)*(y1-y2);
}
//--------------------------------------------------------------------------------------------------
// Compute barycentric coordinates (area coordinates) (u, v, w) for
// point p with respect to triangle (t0, t1, t2)
// These can be used as weights for interpolating scalar values across the triangle
// Based on section 3.4 in "Real Time collision detection" by Christer Ericson
//--------------------------------------------------------------------------------------------------
cvf::Vec3d GeometryTools::barycentricCoords(const cvf::Vec3d& t0, const cvf::Vec3d& t1, const cvf::Vec3d& t2, const cvf::Vec3d& p)
{
// Unnormalized triangle normal
cvf::Vec3d m = (t1 - t0 ^ t2 - t0);
// Absolute components for determining projection plane
int X = 0, Y = 1, Z = 2;
Z = findClosestAxis(m);
switch (Z)
{
case 0: X = 1; Y = 2; break; // x is largest, project to the yz plane
case 1: X = 0; Y = 2; break; // y is largest, project to the xz plane
case 2: X = 0; Y = 1; break; // z is largest, project to the xy plane
}
// Compute areas in plane of largest projection
// Nominators and one-over-denominator for u and v ratios
double nu, nv, ood;
nu = TriArea2D(p[X], p[Y], t1[X], t1[Y], t2[X], t2[Y]); // Area of PBC in yz plane
nv = TriArea2D(p[X], p[Y], t2[X], t2[Y], t0[X], t0[Y]); // Area of PCA in yz plane
ood = 1.0f / m[Z]; // 1/(2*area of ABC in yz plane)
if (Z == 1) ood = -ood; // For some reason not explained
// Normalize
m[0] = nu * ood;
m[1] = nv * ood;
m[2] = 1.0f - m[0] - m[1];
return m;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void GeometryTools::addMidEdgeNodes(std::list<std::pair<cvf::uint, bool> >* polygon, const cvf::Vec3dArray& nodes, EdgeSplitStorage& edgeSplitStorage, std::vector<cvf::Vec3d>* createdVertexes)
{
size_t newVertexIndex = nodes.size() + createdVertexes->size();
std::list<std::pair<cvf::uint, bool> >::iterator it;
std::list<std::pair<cvf::uint, bool> >::iterator it2;
cvf::Vec3d midEdgeCoord(0,0,0);
size_t midPointIndex = cvf::UNDEFINED_UINT;
for (it = polygon->begin(); it != polygon->end(); ++it)
{
it2 = it;
++it2; if (it2 == polygon->end()) it2 = polygon->begin();
// Find or Create and add a mid-edge node
if (!edgeSplitStorage.findSplitPoint(it->first, it2->first, &midPointIndex))
{
midEdgeCoord.setZero();
midEdgeCoord += (it->first < nodes.size()) ? nodes[it->first] : (*createdVertexes)[it->first - nodes.size()];
midEdgeCoord += (it2->first < nodes.size()) ? nodes[it2->first] : (*createdVertexes)[it2->first - nodes.size()];
midEdgeCoord *= 0.5;
midPointIndex = newVertexIndex;
createdVertexes->push_back(midEdgeCoord);
++newVertexIndex;
edgeSplitStorage.addSplitPoint(it->first, it2->first, midPointIndex);
}
if (it2 != polygon->begin())
polygon->insert(it2, std::make_pair((cvf::uint)midPointIndex, true));
else
polygon->insert(polygon->end(), std::make_pair((cvf::uint)midPointIndex, true));
++it;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void EdgeSplitStorage::setVertexCount(size_t size)
{
m_edgeSplitMap.resize(size);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool EdgeSplitStorage::findSplitPoint(size_t edgeP1Index, size_t edgeP2Index, size_t* splitPointIndex)
{
canonizeAddress(edgeP1Index, edgeP2Index);
CVF_ASSERT(edgeP1Index < m_edgeSplitMap.size());
std::map< size_t, size_t >::iterator it;
it = m_edgeSplitMap[edgeP1Index].find(edgeP2Index);
if (it == m_edgeSplitMap[edgeP1Index].end()) return false;
*splitPointIndex = it->second;
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void EdgeSplitStorage::addSplitPoint(size_t edgeP1Index, size_t edgeP2Index, size_t splitPointIndex)
{
canonizeAddress(edgeP1Index, edgeP2Index);
CVF_ASSERT(edgeP1Index < m_edgeSplitMap.size());
m_edgeSplitMap[edgeP1Index][edgeP2Index] = splitPointIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void EdgeSplitStorage::canonizeAddress(size_t& edgeP1Index, size_t& edgeP2Index)
{
if (edgeP1Index > edgeP2Index)
{
size_t tmp;
tmp = edgeP1Index;
edgeP1Index = edgeP2Index;
edgeP2Index = tmp;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
EarClipTesselator::EarClipTesselator():
m_X(-1),
m_Y(-1),
m_areaTolerance(1e-12),
m_nodeCoords(NULL)
{
}
//--------------------------------------------------------------------------------------------------
/// \brief Do the main processing/actual triangulation
/// \param triangleIndices Array that will receive the indices of the triangles resulting from the triangulation
/// \return true when a tesselation was successully created
//--------------------------------------------------------------------------------------------------
bool EarClipTesselator::calculateTriangles( std::vector<size_t>* triangleIndices )
{
CVF_ASSERT(m_nodeCoords != NULL);
CVF_ASSERT(m_X > -1 && m_Y > -1);
size_t numVertices = m_polygonIndices.size();
if (numVertices < 3) return false;
// We want m_polygonIndices to be a counter-clockwise polygon to make the validation test work
if (calculatePolygonArea() < 0 )
{
m_polygonIndices.reverse();
}
std::list<size_t>::iterator u, v, w;
// If we loop two times around polygon without clipping a single triangle we are toast.
size_t count = 2*numVertices; // error detection
v = m_polygonIndices.end(); //nv - 1;
--v;
while (numVertices > 2)
{
// if we loop, it is probably a non-simple polygon
if (count <= 0 )
{
// Triangulate: ERROR - probable bad polygon!
return false;
}
--count;
// Three consecutive vertices in current polygon, <u,v,w>
// previous
u = v;
if (u == m_polygonIndices.end()) u = m_polygonIndices.begin(); // if (nv <= u) u = 0;
// new v
v = u; ++v; //u + 1;
if (v == m_polygonIndices.end()) v = m_polygonIndices.begin(); //if (nv <= v) v = 0;
// next
w = v; ++w; //v + 1;
if (w == m_polygonIndices.end()) w = m_polygonIndices.begin(); //if (nv <= w) w = 0;
if ( isTriangleValid(u, v, w) )
{
// Indices of the vertices
triangleIndices->push_back(*u);
triangleIndices->push_back(*v);
triangleIndices->push_back(*w);
// Remove v from remaining polygon
m_polygonIndices.erase(v);
v = w;
numVertices--;
// Resets error detection counter
count = 2*numVertices;
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
/// Is this a valid triangle ? ( No points inside, and points not on a line. )
//--------------------------------------------------------------------------------------------------
bool EarClipTesselator::isTriangleValid( std::list<size_t>::const_iterator u, std::list<size_t>::const_iterator v, std::list<size_t>::const_iterator w) const
{
CVF_ASSERT(m_X > -1 && m_Y > -1);
cvf::Vec3d A = (*m_nodeCoords)[*u];
cvf::Vec3d B = (*m_nodeCoords)[*v];
cvf::Vec3d C = (*m_nodeCoords)[*w];
if ( m_areaTolerance > (((B[m_X]-A[m_X])*(C[m_Y]-A[m_Y])) - ((B[m_Y]-A[m_Y])*(C[m_X]-A[m_X]))) ) return false;
std::list<size_t>::const_iterator c;
std::list<size_t>::const_iterator outside;
for (c = m_polygonIndices.begin(); c != m_polygonIndices.end(); ++c)
{
// The polygon points that actually make up the triangle candidate does not count
// (but the same points on different positions in the polygon does!
// Except those one off the triangle, that references the start or end of the triangle)
if ( (c == u) || (c == v) || (c == w)) continue;
// Originally the below tests was not included which resulted in missing triangles sometimes
outside = w; ++outside; if (outside == m_polygonIndices.end()) outside = m_polygonIndices.begin();
if (c == outside && *c == *u)
{
continue;
}
outside = u; if (outside == m_polygonIndices.begin()) outside = m_polygonIndices.end(); --outside;
if (c == outside && *c == *w)
{
continue;
}
cvf::Vec3d P = (*m_nodeCoords)[*c];
if (isPointInsideTriangle(A, B, C, P)) return false;
}
return true;
}
//--------------------------------------------------------------------------------------------------
/// Decides if a point P is inside of the triangle defined by A, B, C.
/// By calculating the "double area" (cross product) of Corner to corner x Corner to point vectors
//--------------------------------------------------------------------------------------------------
bool EarClipTesselator::isPointInsideTriangle(const cvf::Vec3d& A, const cvf::Vec3d& B, const cvf::Vec3d& C, const cvf::Vec3d& P) const
{
CVF_ASSERT(m_X > -1 && m_Y > -1);
double ax = C[m_X] - B[m_X]; double ay = C[m_Y] - B[m_Y];
double bx = A[m_X] - C[m_X]; double by = A[m_Y] - C[m_Y];
double cx = B[m_X] - A[m_X]; double cy = B[m_Y] - A[m_Y];
double apx= P[m_X] - A[m_X]; double apy= P[m_Y] - A[m_Y];
double bpx= P[m_X] - B[m_X]; double bpy= P[m_Y] - B[m_Y];
double cpx= P[m_X] - C[m_X]; double cpy= P[m_Y] - C[m_Y];
double aCROSSbp = ax*bpy - ay*bpx;
double cCROSSap = cx*apy - cy*apx;
double bCROSScp = bx*cpy - by*cpx;
double tol = 0;
return ((aCROSSbp >= tol) && (bCROSScp >= tol) && (cCROSSap >= tol));
};
//--------------------------------------------------------------------------------------------------
/// Computes area of the currently stored 2D polygon/contour
//--------------------------------------------------------------------------------------------------
double EarClipTesselator::calculatePolygonArea() const
{
CVF_ASSERT(m_X > -1 && m_Y > -1);
double A = 0;
std::list<size_t>::const_iterator p = m_polygonIndices.end();
--p;
std::list<size_t>::const_iterator q = m_polygonIndices.begin();
while (q != m_polygonIndices.end())
{
A += (*m_nodeCoords)[*p][m_X] * (*m_nodeCoords)[*q][m_Y] - (*m_nodeCoords)[*q][m_X]*(*m_nodeCoords)[*p][m_Y];
p = q;
q++;
}
return A*0.5;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void EarClipTesselator::setNormal(const cvf::Vec3d& polygonNormal)
{
int Z = GeometryTools::findClosestAxis(polygonNormal);
m_X = (Z + 1) % 3;
m_Y = (Z + 2) % 3;
m_polygonNormal = polygonNormal;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void EarClipTesselator::setPolygonIndices(const std::list<size_t>& polygon)
{
m_polygonIndices = polygon;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void EarClipTesselator::setPolygonIndices(const std::vector<size_t>& polygon)
{
size_t i;
for (i = 0; i < polygon.size(); ++i)
{
m_polygonIndices.push_back(polygon[i]);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void EarClipTesselator::setMinTriangleArea(double areaTolerance)
{
m_areaTolerance = 2*areaTolerance; // Convert to trapesoidal area
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void EarClipTesselator::setGlobalNodeArray(const cvf::Vec3dArray& nodeCoords)
{
m_nodeCoords = &nodeCoords;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
FanEarClipTesselator::FanEarClipTesselator() :
m_centerNodeIndex(std::numeric_limits<size_t>::max())
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void FanEarClipTesselator::setCenterNode(size_t centerNodeIndex)
{
m_centerNodeIndex = centerNodeIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool FanEarClipTesselator::calculateTriangles(std::vector<size_t>* triangles)
{
CVF_ASSERT(m_centerNodeIndex != std::numeric_limits<size_t>::max());
CVF_ASSERT(m_nodeCoords != NULL);
CVF_ASSERT(m_X > -1 && m_Y > -1);
size_t nv = m_polygonIndices.size();
if (nv < 3) return false;
// We want m_polygonIndices to be a counter-clockwise polygon to make the validation test work
if (calculatePolygonArea() < 0 )
{
m_polygonIndices.reverse();
}
std::list<size_t>::const_iterator it1;
std::list<size_t>::const_iterator it2;
std::list< std::list<size_t> > restPolygons;
bool wasPreviousTriangleValid = true;
for (it1 = m_polygonIndices.begin(); it1 != m_polygonIndices.end(); it1++)
{
it2 = it1;
it2++;
if (it2 == m_polygonIndices.end()) it2 = m_polygonIndices.begin();
if (isTriangleValid(*it1, *it2, m_centerNodeIndex))
{
triangles->push_back(*it1);
triangles->push_back(*it2);
triangles->push_back(m_centerNodeIndex);
wasPreviousTriangleValid = true;
}
else
{
if (wasPreviousTriangleValid)
{
// Create new rest polygon.
restPolygons.push_back(std::list<size_t>());
restPolygons.back().push_back(m_centerNodeIndex);
restPolygons.back().push_back(*it1);
restPolygons.back().push_back(*it2);
}
else
{
restPolygons.back().push_back(*it2);
}
}
}
EarClipTesselator triMaker;
triMaker.setNormal(m_polygonNormal);
triMaker.setMinTriangleArea(m_areaTolerance);
triMaker.setGlobalNodeArray(*m_nodeCoords);
std::list< std::list<size_t> >::iterator rpIt;
for (rpIt = restPolygons.begin(); rpIt != restPolygons.end(); ++rpIt)
{
triMaker.setPolygonIndices(*rpIt);
triMaker.calculateTriangles(triangles);
}
return true;
}
//--------------------------------------------------------------------------------------------------
/// This needs to be rewritten because we need to test for crossing edges, not only point inside.
/// In addition the test for polygon
//--------------------------------------------------------------------------------------------------
bool FanEarClipTesselator::isTriangleValid(size_t u, size_t v, size_t w)
{
CVF_ASSERT(m_X > -1 && m_Y > -1);
cvf::Vec3d A = (*m_nodeCoords)[u];
cvf::Vec3d B = (*m_nodeCoords)[v];
cvf::Vec3d C = (*m_nodeCoords)[w];
if ( m_areaTolerance > (((B[m_X]-A[m_X])*(C[m_Y]-A[m_Y])) - ((B[m_Y]-A[m_Y])*(C[m_X]-A[m_X]))) ) return false;
std::list<size_t>::const_iterator c;
for (c = m_polygonIndices.begin(); c != m_polygonIndices.end(); ++c)
{
// The polygon points that actually make up the triangle candidate does not count
// (but the same points on different positions in the polygon does! )
// Todo so this test below is to accepting !! Bug !!
if ( (*c == u) || (*c == v) || (*c == w)) continue;
cvf::Vec3d P = (*m_nodeCoords)[*c];
if (isPointInsideTriangle(A, B, C, P)) return false;
}
return true;
}
}

View File

@@ -0,0 +1,167 @@
#pragma once
#include "cvfBase.h"
#include "cvfArray.h"
#include <list>
#include <map>
#include "cvfArrayWrapperConst.h"
namespace cvf
{
class EdgeSplitStorage;
template <typename IndexType> class EdgeIntersectStorage;
class GeometryTools
{
public:
static cvf::Vec3d computeFaceCenter(const cvf::Vec3d& v0, const cvf::Vec3d& v1, const cvf::Vec3d& v2, const cvf::Vec3d& v3);
static double linePointSquareDist(const cvf::Vec3d& p1, const cvf::Vec3d& p2, const cvf::Vec3d& p3);
static int intersectLineSegmentTriangle( const cvf::Vec3d p0, const cvf::Vec3d p1,
const cvf::Vec3d t0, const cvf::Vec3d t1, const cvf::Vec3d t2,
cvf::Vec3d* intersectionPoint );
static cvf::Vec3d barycentricCoords(const cvf::Vec3d& t0, const cvf::Vec3d& t1, const cvf::Vec3d& t2, const cvf::Vec3d& p);
static int findClosestAxis(const cvf::Vec3d& vec );
static double getAngle(const cvf::Vec3d& positiveNormalAxis, const cvf::Vec3d& v1, const cvf::Vec3d& v2);
static double getAngle(const cvf::Vec3d& v1, const cvf::Vec3d& v2);
enum IntersectionStatus
{
NO_INTERSECTION,
LINES_INTERSECT_OUTSIDE,
LINES_TOUCH,
LINES_CROSSES,
LINES_OVERLAP
};
static void addMidEdgeNodes(std::list<std::pair<cvf::uint, bool> >* polygon, const cvf::Vec3dArray& nodes, EdgeSplitStorage& edgeSplitStorage, std::vector<cvf::Vec3d>* createdVertexes);
template<typename VerticeArrayType, typename IndexType>
static bool insertVertexInPolygon( std::vector<IndexType> * polygon,
ArrayWrapperConst<VerticeArrayType, cvf::Vec3d> nodeCoords,
IndexType vertexIndex,
double tolerance);
static IntersectionStatus inPlaneLineIntersect3D(const cvf::Vec3d& planeNormal,
const cvf::Vec3d& p1, const cvf::Vec3d& p2, const cvf::Vec3d& p3, const cvf::Vec3d& p4,
cvf::Vec3d* intersectionPoint, double* fractionAlongLine1, double* fractionAlongLine2,
double tolerance = 1e-6);
template<typename VerticeArrayType, typename PolygonArrayType, typename IndexType>
static bool isPointTouchingIndexedPolygon( const cvf::Vec3d& polygonNormal,
ArrayWrapperConst<VerticeArrayType, cvf::Vec3d> vertices,
ArrayWrapperConst<PolygonArrayType, IndexType> indices,
const cvf::Vec3d& point,
int* touchedEdgeIndex,
double tolerance = 1e-6);
template<typename VerticeArrayType, typename IndexType>
static bool calculateOverlapPolygonOfTwoQuads( std::vector<IndexType> * polygon,
std::vector<cvf::Vec3d>* createdVertexes,
EdgeIntersectStorage<IndexType>* edgeIntersectionStorage,
ArrayWrapperConst<VerticeArrayType, cvf::Vec3d> nodes,
const IndexType cv1CubeFaceIndices[4],
const IndexType cv2CubeFaceIndices[4],
double tolerance);
template<typename VerticeArrayType, typename PolygonArrayType, typename IndexType>
static void calculatePartiallyFreeCubeFacePolygon(ArrayWrapperConst<VerticeArrayType, cvf::Vec3d> nodeCoords,
ArrayWrapperConst<PolygonArrayType, IndexType> completeFacePolygon,
const cvf::Vec3d& faceNormal,
const std::vector< std::vector<IndexType>* >& faceOverlapPolygons,
const std::vector<bool> faceOverlapPolygonWindingSameAsCubeFaceFlags,
std::vector<IndexType>* partialFacePolygon,
bool* m_partiallyFreeCubeFaceHasHoles);
};
template <typename IndexType>
class EdgeIntersectStorage
{
public:
void setVertexCount(size_t size);
bool findIntersection( IndexType e1P1, IndexType e1P2, IndexType e2P1, IndexType e2P2,
IndexType* vxIndexIntersectionPoint, GeometryTools::IntersectionStatus* intersectionStatus,
double* fractionAlongEdge1, double* fractionAlongEdge2);
void addIntersection( IndexType e1P1, IndexType e1P2, IndexType e2P1, IndexType e2P2,
IndexType vxIndexIntersectionPoint, GeometryTools::IntersectionStatus intersectionStatus,
double fractionAlongEdge1, double fractionAlongEdge2);
private:
struct IntersectData
{
IndexType intersectionPointIndex;
GeometryTools::IntersectionStatus intersectionStatus;
double fractionAlongEdge1;
double fractionAlongEdge2;
};
void canonizeAddress(IndexType& e1P1, IndexType& e1P2, IndexType& e2P1, IndexType& e2P2, bool& flipE1, bool& flipE2, bool& flipE1E2);
// A map containing the intersection data. The addressing is :
// ( when leastVxIdxEdge1 < leastVxIdxEdge2 )
// leastVxIdxEdge1, largestVxIdxEdge1, leastVxIdxEdge2, largestVxIdxEdge2, { vxIdxIntersection, fractionAlongEdg1, fractionAlonEdge2 }
std::vector< std::map<IndexType, std::map<IndexType, std::map<IndexType, IntersectData > > > > m_edgeIntsectMap;
};
class EdgeSplitStorage
{
public:
void setVertexCount(size_t size);
bool findSplitPoint(size_t edgeP1Index, size_t edgeP2Index, size_t* splitPointIndex);
void addSplitPoint(size_t edgeP1Index, size_t edgeP2Index, size_t splitPointIndex);
private:
void canonizeAddress(size_t& e1P1, size_t& e1P2);
// Least VxIdx, LargestVxIdx, VertexIdx of splitpoint
std::vector< std::map< size_t, size_t > > m_edgeSplitMap;
};
class EarClipTesselator
{
public:
EarClipTesselator();
void setNormal(const cvf::Vec3d& polygonNormal );
void setMinTriangleArea(double areaTolerance);
void setGlobalNodeArray(const cvf::Vec3dArray& nodeCoords);
void setPolygonIndices(const std::list<size_t>& polygon);
void setPolygonIndices(const std::vector<size_t>& polygon);
virtual bool calculateTriangles(std::vector<size_t>* triangles);
protected:
bool isTriangleValid( std::list<size_t>::const_iterator u, std::list<size_t>::const_iterator v, std::list<size_t>::const_iterator w) const;
bool isPointInsideTriangle(const cvf::Vec3d& A, const cvf::Vec3d& B, const cvf::Vec3d& C, const cvf::Vec3d& P) const;
double calculatePolygonArea() const;
protected:
std::list<size_t> m_polygonIndices;
const cvf::Vec3dArray* m_nodeCoords;
int m_X, m_Y; // Index shift in vector to do simple 2D projection
cvf::Vec3d m_polygonNormal;
double m_areaTolerance;
};
class FanEarClipTesselator : public EarClipTesselator
{
public:
FanEarClipTesselator();
void setCenterNode(size_t centerNodeIndex );
virtual bool calculateTriangles(std::vector<size_t>* triangles);
private:
bool isTriangleValid( size_t u, size_t v, size_t w);
size_t m_centerNodeIndex;
};
}
#include "cvfGeometryTools.inl"

View File

@@ -0,0 +1,957 @@
#include <cmath>
#pragma warning (disable : 4503)
namespace cvf
{
//--------------------------------------------------------------------------------------------------
/// Inserts the vertex into the polygon if it fits along one of the edges within the tolerance.
/// The method returns true if it was inserted, or if it was already in the polygon, or if it was
/// within the tolerance of an existing vertex in the polygon.
/// In the latter situation it replaces the previous vertex in the polygon.
///
/// Todo: If a vertex is replaced, the VxToCv map in TimeStepGeometry should be updated
//--------------------------------------------------------------------------------------------------
template<typename VerticeArrayType, typename IndexType>
bool GeometryTools::insertVertexInPolygon( std::vector<IndexType> * polygon,
ArrayWrapperConst<VerticeArrayType, cvf::Vec3d> nodeCoords,
IndexType vertexIndex,
double tolerance)
{
CVF_ASSERT(polygon);
// Check if vertex is directly included already
for(typename std::vector<IndexType>::iterator it = polygon->begin(); it != polygon->end(); ++it)
{
if (*it == vertexIndex) return true;
}
#if 1
// Check if the new point is within tolerance of one of the polygon vertices
bool existsOrInserted = false;
for(typename std::vector<IndexType>::iterator it = polygon->begin(); it != polygon->end(); ++it)
{
if ( (nodeCoords[*it] - nodeCoords[vertexIndex]).length() < tolerance)
{
if (vertexIndex < *it) *it = vertexIndex;
existsOrInserted = true;
}
}
if (existsOrInserted) return true;
#endif
// Copy the start polygon to a list
std::list<IndexType> listPolygon;
for (size_t pcIdx = 0; pcIdx < polygon->size(); ++pcIdx)
{
listPolygon.push_back((*polygon)[pcIdx]);
}
// Insert vertex in polygon if the distance to one of the edges is small enough
typename std::list<IndexType >::iterator it2;
typename std::list<IndexType >::iterator insertBefore;
for (typename std::list<IndexType >::iterator it = listPolygon.begin(); it != listPolygon.end(); ++it)
{
it2 = it;
++it2; insertBefore = it2; if (it2 == listPolygon.end()) it2 = listPolygon.begin();
double sqDistToLine = GeometryTools::linePointSquareDist(nodeCoords[*it], nodeCoords[*it2], nodeCoords[vertexIndex]);
if (fabs(sqDistToLine) < tolerance*tolerance )
{
it = listPolygon.insert(insertBefore, vertexIndex);
existsOrInserted = true;
}
}
// Write polygon back into the vector
polygon->clear();
for (typename std::list<IndexType >::iterator it = listPolygon.begin(); it != listPolygon.end(); ++it)
{
polygon->push_back(*it);
}
return existsOrInserted;
}
//--------------------------------------------------------------------------------------------------
/// \brief Test if a point touches a polygon within the specified tolerance
///
/// \param polygonNorm Polygon normal
/// \param pPolygonVerts Array of polygon vertice coordinates
/// \param piVertexIndices Array of integer node indices for this polygon
/// \param iNumVerts Number of vertices in polygon
/// \param point The point to be checked
/// \param tolerance Tolerance in length
/// \param touchedEdgeIndex returns -1 if point is inside, and edge index if point touches an edge.
/// \return true if point lies inside or on the border of the polygon.
///
/// \assumpt Assumes that the polygon is planar
/// \comment First check if point is on an edge, Then check if it is inside by
/// counting the number of times a ray from point along positive X axis
/// crosses an edge. Odd number says inside.
/// \author SP (really by Eric Haines) and JJS
//--------------------------------------------------------------------------------------------------
template<typename VerticeArrayType, typename PolygonArrayType, typename IndexType>
bool GeometryTools::isPointTouchingIndexedPolygon( const cvf::Vec3d& polygonNormal,
cvf::ArrayWrapperConst<VerticeArrayType, cvf::Vec3d> vertices,
cvf::ArrayWrapperConst<PolygonArrayType, IndexType> indices,
const cvf::Vec3d& point,
int* touchedEdgeIndex,
double tolerance)
{
size_t numIndices = indices.size();
int Z = findClosestAxis(polygonNormal);
int X = (Z + 1) % 3;
int Y = (Z + 2) % 3;
int crossings;
int xBelowVx0;
int yBelowVx0;
int yBelowVx1 = 0;
const double* vtx0;
const double* vtx1 = NULL;
double dv0;
cvf::uint j;
// Check if point is on an edge or vertex
size_t firstIdx;
size_t secondIdx;
CVF_TIGHT_ASSERT(touchedEdgeIndex);
*touchedEdgeIndex = -1;
for (firstIdx = 0, secondIdx = 1; firstIdx < numIndices; ++firstIdx, ++secondIdx)
{
if (secondIdx >= numIndices) secondIdx = 0;
const cvf::Vec3d& vx0 = vertices[indices[firstIdx]];
const cvf::Vec3d& vx1 = vertices[indices[secondIdx]];
double sqDist = GeometryTools::linePointSquareDist(vx0, vx1, point);
if (sqDist < tolerance*tolerance)
{
*touchedEdgeIndex = static_cast<int>(firstIdx);
return true;
}
}
vtx0 = vertices[indices[numIndices-1]].ptr();
// get test bit for above/below Y axis. Y of Point is under Y of vtx0
yBelowVx0 = ( dv0 = vtx0[Y] - point[Y] ) >= 0.0;
crossings = 0;
for (j = 0; j < numIndices; j++)
{
// cleverness: bobble between filling endpoints of edges, so that the previous edge's shared endpoint is maintained.
if (j & 0x1)
{
vtx0 = vertices[indices[j]].ptr();
yBelowVx0 = (dv0 = vtx0[Y] - point[Y]) >= 0.0;
}
else
{
vtx1 = vertices[indices[j]].ptr();
yBelowVx1 = (vtx1[Y] >= point[Y]);
}
// check if Y of point is between Y of Vx0 and Vx1
if (yBelowVx0 != yBelowVx1)
{
// check if X of point is not between X of Vx0 and Vx1
if ( (xBelowVx0 = (vtx0[X] >= point[X])) == (vtx1[X] >= point[X]) )
{
if (xBelowVx0) crossings++;
}
else
{
// compute intersection of polygon segment with X ray, note if > point's X.
crossings += (vtx0[X] - dv0*(vtx1[X] - vtx0[X])/(vtx1[Y] - vtx0[Y])) >= point[X];
}
}
}
// test if crossings is odd. If we care about its winding number > 0, then just: inside_flag = crossings > 0;
if (crossings & 0x01) return true;
return false;
}
//--------------------------------------------------------------------------------------------------
/// Returns true if we get an actual polygon
/// The returned polygon will keep the winding from the first face.
/// The second face must have opposite winding of the first
//--------------------------------------------------------------------------------------------------
template<typename VerticeArrayType, typename IndexType>
bool GeometryTools::calculateOverlapPolygonOfTwoQuads(std::vector<IndexType> * polygon,
std::vector<cvf::Vec3d>* createdVertexes,
EdgeIntersectStorage<IndexType>* edgeIntersectionStorage,
ArrayWrapperConst<VerticeArrayType, cvf::Vec3d> nodes,
const IndexType cv1CubeFaceIndices[4],
const IndexType cv2CubeFaceIndices[4],
double tolerance)
{
CVF_ASSERT(polygon);
CVF_ASSERT(createdVertexes);
// Topology analysis
IndexType newVertexIndex = static_cast<IndexType>(nodes.size() + createdVertexes->size());
bool cv1VxTouchCv2[4] = { false, false, false, false };
bool cv2VxTouchCv1[4] = { false, false, false, false };
int cv1VxTouchCv2Edge[4] = { -1, -1, -1, -1 };
int cv2VxTouchCv1Edge[4] = { -1, -1, -1, -1 };
int cv1Idx, cv2Idx;
int numMatchedNodes = 0;
// First check for complete topological match.
for (cv1Idx = 0 ; cv1Idx < 4 ; ++cv1Idx)
{
bool found = false;
for (cv2Idx = 0; cv2Idx < 4; ++cv2Idx)
{
if (cv1CubeFaceIndices[cv1Idx] == cv2CubeFaceIndices[cv2Idx])
{
cv1VxTouchCv2[cv1Idx] = true;
cv2VxTouchCv1[cv2Idx] = true;
found = true;
++numMatchedNodes;
continue;
}
}
}
if (numMatchedNodes >= 4) // Todo: Handle collapsed cells
{
int k;
for (k = 0; k < 4; ++k)
{
polygon->push_back(cv1CubeFaceIndices[k]);
}
return true;
}
cvf::Vec3d diag1 = nodes[cv1CubeFaceIndices[2]] - nodes[cv1CubeFaceIndices[0]];
cvf::Vec3d diag2 = nodes[cv1CubeFaceIndices[3]] - nodes[cv1CubeFaceIndices[1]];
cvf::Vec3d normal = diag1^diag2;
int numCv1VxesOnCv2 = numMatchedNodes;
int numCv2VxesOnCv1 = numMatchedNodes;
for (cv1Idx = 0 ; cv1Idx < 4 ; ++cv1Idx)
{
if (!cv1VxTouchCv2[cv1Idx])
{
cv1VxTouchCv2[cv1Idx] = GeometryTools::isPointTouchingIndexedPolygon(normal,
nodes,
wrapArrayConst(cv2CubeFaceIndices, 4),
nodes[cv1CubeFaceIndices[cv1Idx]],
&(cv1VxTouchCv2Edge[cv1Idx]),
tolerance);
if (cv1VxTouchCv2[cv1Idx]) ++numCv1VxesOnCv2;
}
if (!cv2VxTouchCv1[cv1Idx])
{
cv2VxTouchCv1[cv1Idx] = GeometryTools::isPointTouchingIndexedPolygon(normal,
nodes,
wrapArrayConst(cv1CubeFaceIndices, 4),
nodes[cv2CubeFaceIndices[cv1Idx]],
&(cv2VxTouchCv1Edge[cv1Idx]),
tolerance);
if (cv2VxTouchCv1[cv1Idx]) ++numCv2VxesOnCv1;
}
}
// Handle case where one of the faces are completely covered by the other
if (numCv1VxesOnCv2 >= 4)
{
int k;
for (k = 0; k < 4; ++k)
{
polygon->push_back(cv1CubeFaceIndices[k]);
}
return true;
}
if (numCv2VxesOnCv1 >= 4)
{
int k;
for (k = 0; k < 4; ++k)
{
polygon->push_back(cv2CubeFaceIndices[k]);
}
return true;
}
// Handle partial coverage
// Algorithm outline as follows:
// Loop over edges in the face of Cv1. Intersect each one with all the edges of the Cv2 face.
// Add first point of the cv1 edge to polygon if it really touches Cv2 ( touch of edge is considered as not touching)
// Add each intersection point along the Cv1 edge if present
// and finally: if the cv1 edge is going out of cv2, the add the cv2 vertexes from that intersection as long as they touch cv1.
int nextCv1Idx = 1;
for (cv1Idx = 0 ; cv1Idx < 4 ; ++cv1Idx, ++nextCv1Idx)
{
if (nextCv1Idx > 3) nextCv1Idx = 0;
if (cv1VxTouchCv2[cv1Idx] && cv1VxTouchCv2Edge[cv1Idx] == -1) // Start of cv1 edge is touching inside the cv2 polygon (not on an cv2 edge)
{
if (polygon->empty() || polygon->back() != cv1CubeFaceIndices[cv1Idx])
{
polygon->push_back(cv1CubeFaceIndices[cv1Idx]);
}
if (cv1VxTouchCv2[nextCv1Idx] && cv1VxTouchCv2Edge[nextCv1Idx] == -1)
{
// Both ends of this cv1 edge is touching inside(not on an edge) cv2 polygon, no intersections possible (assuming convex cube-face)
// Continue with next Cv1-edge.
continue;
}
}
// Find intersection(s) on this edge
std::vector<IndexType> intersectionVxIndices;
std::vector<int> intersectedCv2EdgeIdxs;
std::vector<double> intersectionFractionsAlongEdge;
int nextCv2Idx = 1;
for (cv2Idx = 0; cv2Idx < 4; ++cv2Idx, ++nextCv2Idx)
{
if (nextCv2Idx > 3) nextCv2Idx = 0;
// Find a possible real intersection point.
cvf::Vec3d intersection(0,0,0);
double fractionAlongEdge1;
GeometryTools::IntersectionStatus intersectStatus = GeometryTools::NO_INTERSECTION;
IndexType intersectionVxIndex = cvf::UNDEFINED_UINT;
// First handle some "trivial" ones to ease the burden for the real intersection calculation
// It could be tested whether it really is necessary to do
if (cv1VxTouchCv2Edge[cv1Idx] == cv2Idx && cv1VxTouchCv2Edge[nextCv1Idx] == cv2Idx )
{
intersectStatus = GeometryTools::LINES_OVERLAP;
fractionAlongEdge1 = 1;
intersectionVxIndex = cv1CubeFaceIndices[nextCv1Idx];
}
else if (cv1VxTouchCv2Edge[cv1Idx] == cv2Idx )
{
// When this happens, the cv1 vertex will already have been added to the polygon
// by the statements in the top of the cv1 edge loop. Should it be treated specially ?
intersectStatus = GeometryTools::LINES_TOUCH;
fractionAlongEdge1 = 0;
intersectionVxIndex = cv1CubeFaceIndices[cv1Idx];
}
else if (cv1VxTouchCv2Edge[nextCv1Idx] == cv2Idx )
{
intersectStatus = GeometryTools::LINES_TOUCH;
fractionAlongEdge1 = 1;
intersectionVxIndex = cv1CubeFaceIndices[nextCv1Idx];
}
else
{
double fractionAlongEdge2;
bool found = false;
if (edgeIntersectionStorage)
found = edgeIntersectionStorage->findIntersection(
cv1CubeFaceIndices[cv1Idx],
cv1CubeFaceIndices[nextCv1Idx],
cv2CubeFaceIndices[cv2Idx],
cv2CubeFaceIndices[nextCv2Idx],
&intersectionVxIndex, &intersectStatus,
&fractionAlongEdge1, &fractionAlongEdge2);
if (!found)
{
intersectStatus = GeometryTools::inPlaneLineIntersect3D(normal,
nodes[cv1CubeFaceIndices[cv1Idx]],
nodes[cv1CubeFaceIndices[nextCv1Idx]],
nodes[cv2CubeFaceIndices[cv2Idx]],
nodes[cv2CubeFaceIndices[nextCv2Idx]],
&intersection, &fractionAlongEdge1, &fractionAlongEdge2,
tolerance);
switch (intersectStatus)
{
case GeometryTools::LINES_CROSSES:
{
intersectionVxIndex = newVertexIndex;
createdVertexes->push_back(intersection);
++newVertexIndex;
}
break;
case GeometryTools::LINES_TOUCH:
{
if (fractionAlongEdge1 <= 0.0) intersectionVxIndex = cv1CubeFaceIndices[cv1Idx];
else if (fractionAlongEdge1 >= 1.0) intersectionVxIndex = cv1CubeFaceIndices[nextCv1Idx];
else if (fractionAlongEdge2 <= 0.0) intersectionVxIndex = cv2CubeFaceIndices[cv2Idx];
else if (fractionAlongEdge2 >= 1.0) intersectionVxIndex = cv2CubeFaceIndices[nextCv2Idx];
else CVF_ASSERT(false); // Tolerance trouble
}
break;
case GeometryTools::LINES_OVERLAP:
{
if (fractionAlongEdge1 <= 0.0) intersectionVxIndex = cv1CubeFaceIndices[cv1Idx];
else if (fractionAlongEdge1 >= 1.0) intersectionVxIndex = cv1CubeFaceIndices[nextCv1Idx];
else if (fractionAlongEdge2 <= 0.0) intersectionVxIndex = cv2CubeFaceIndices[cv2Idx];
else if (fractionAlongEdge2 >= 1.0) intersectionVxIndex = cv2CubeFaceIndices[nextCv2Idx];
else CVF_ASSERT(false); // Tolerance trouble
}
break;
default:
break;
}
if(edgeIntersectionStorage)
edgeIntersectionStorage->addIntersection( cv1CubeFaceIndices[cv1Idx],
cv1CubeFaceIndices[nextCv1Idx],
cv2CubeFaceIndices[cv2Idx],
cv2CubeFaceIndices[nextCv2Idx],
intersectionVxIndex, intersectStatus,
fractionAlongEdge1, fractionAlongEdge2);
}
}
// Store data for each intersection along the Cv1-edge
if ( (intersectStatus == GeometryTools::LINES_CROSSES)
|| (intersectStatus == GeometryTools::LINES_TOUCH)
|| (intersectStatus == GeometryTools::LINES_OVERLAP) )
{
CVF_ASSERT(intersectionVxIndex != cvf::UNDEFINED_UINT);
intersectionFractionsAlongEdge.push_back(fractionAlongEdge1);
intersectedCv2EdgeIdxs.push_back(cv2Idx);
intersectionVxIndices.push_back(intersectionVxIndex);
}
}
// Insert the intersections into the polygon in the correct order along the Cv1 edge.
// Find the last intersection in order to possibly continue the polygon along Cv2 into Cv1
size_t i;
size_t lastIntersection = std::numeric_limits<size_t>::max();
double largestFraction = -1;
for (i = 0; i < intersectionFractionsAlongEdge.size(); ++i)
{
if (intersectionFractionsAlongEdge[i] > largestFraction)
{
lastIntersection = i;
largestFraction = intersectionFractionsAlongEdge[i];
}
}
// Insert indices to the new intersection vertices into the polygon of
// this connection according to fraction along edge
std::map<double,IndexType> sortingMap;
for (i = 0; i < intersectionFractionsAlongEdge.size(); ++i)
{
sortingMap[intersectionFractionsAlongEdge[i]] = intersectionVxIndices[i];
}
typename std::map<double, IndexType>::iterator it;
for (it = sortingMap.begin(); it != sortingMap.end(); ++it)
{
if (polygon->empty() || polygon->back() != it->second)
{
polygon->push_back(it->second);
}
}
// Then if the Cv1 edge is going out of Cv2, add to the polygon, all the Cv2 face vertex-indices
// from the intersection that touches Cv1.
// if cv1 edge in any way touches cv2 and ends up outside, it went out.
/*
if cv1 edge is going out of cv2 then
if intersected cv2 edge has endpoint touching cv1 then
add endpoint to polygon. continue to add next endpoint until it does not touch Cv1
*/
if ( !cv1VxTouchCv2[nextCv1Idx]
&& ( cv1VxTouchCv2[cv1Idx] || ( intersectedCv2EdgeIdxs.size() ) ) ) // Two touches along edge also qualifies
{
if(lastIntersection < intersectedCv2EdgeIdxs.size())
{
cv2Idx = intersectedCv2EdgeIdxs[lastIntersection];
int count = 0;
// Continue the polygon along the Cv2 edges as long as they touch cv1.
// Depending on the faces having opposite winding, which is guaranteed as long as
// no intersecting CVs share a connection
while (cv2VxTouchCv1[cv2Idx] && count < 4 && (cv2VxTouchCv1Edge[cv2Idx] == -1)) // Touch of edge is regarded as being outside, so we must stop
{
if (polygon->empty() || polygon->back() != cv2CubeFaceIndices[cv2Idx])
{
polygon->push_back(cv2CubeFaceIndices[cv2Idx]);
}
--cv2Idx;
if (cv2Idx < 0 ) cv2Idx = 3;
++count;
}
}
else
{
CVF_ASSERT(lastIntersection < intersectedCv2EdgeIdxs.size());
}
}
}
if (polygon->size() > 2)
{
if (polygon->back() == polygon->front()) polygon->pop_back();
}
// Sanity checks
if (polygon->size() < 3)
{
// cvf::Trace::show(cvf::String("Degenerated connection polygon detected. (Less than 3 vertexes) Cv's probably not in contact: %1 , %2").arg(m_ownerCvId).arg(m_neighborCvId));
polygon->clear();
return false;
}
return true;
}
//--------------------------------------------------------------------------------------------------
/// This method assumes that all intersection and mid edge vertexes are created an are already
/// merged into all the polygons. We can also assume that all the connection polygons are completely
/// inside (or sharing edges with) the cube face polygon initially
//--------------------------------------------------------------------------------------------------
#define DEBUG_PRINT 0
//template <typename NodeArrayType, typename NodeType, typename IndicesArrayType, typename IndicesType>
//void setup( ArrayWrapper<NodeArrayType, NodeType> nodeArray, ArrayWrapper<IndicesArrayType, IndicesType> indices)
template<typename VerticeArrayType, typename PolygonArrayType, typename IndexType>
void GeometryTools::calculatePartiallyFreeCubeFacePolygon(ArrayWrapperConst<VerticeArrayType, cvf::Vec3d> nodeCoords,
ArrayWrapperConst<PolygonArrayType, IndexType> completeFacePolygon,
const cvf::Vec3d& faceNormal,
const std::vector< std::vector<IndexType>* >& faceOverlapPolygons,
const std::vector<bool> faceOverlapPolygonWindingSameAsCubeFaceFlags,
std::vector<IndexType>* partialFacePolygon,
bool* m_partiallyFreeCubeFaceHasHoles)
{
// Vertex Index to position in polygon
typedef std::map< IndexType, typename std::vector<IndexType>::const_iterator > VxIdxToPolygonPositionMap;
CVF_ASSERT(m_partiallyFreeCubeFaceHasHoles);
CVF_ASSERT(partialFacePolygon != NULL);
// Copy the start polygon
std::list<IndexType> resultPolygon;
for (size_t pcIdx = 0; pcIdx < completeFacePolygon.size(); ++pcIdx)
{
resultPolygon.push_back(completeFacePolygon[pcIdx]);
}
// First build search maps to fast find whether and where an index is positioned in a polygon
// Map from Vertex-index to position in polygon
std::vector< VxIdxToPolygonPositionMap > polygonSearchMaps;
std::vector<bool> isConnectionPolygonMerged;
polygonSearchMaps.resize(faceOverlapPolygons.size());
isConnectionPolygonMerged.resize(faceOverlapPolygons.size(), false);
// Build search maps
{
size_t count;
for (size_t i = 0; i < faceOverlapPolygons.size(); ++i)
{
count = 0;
for (typename std::vector<IndexType >::const_iterator pcIt = faceOverlapPolygons[i]->begin();
pcIt != faceOverlapPolygons[i]->end();
++pcIt)
{
polygonSearchMaps[i][*pcIt] = pcIt;
++count;
}
if (count < 3) isConnectionPolygonMerged[i] = true; // Ignore false polygons
}
}
#if DEBUG_PRINT
{
cvf::Trace::show("Circumference polygon: ");
std::list<IndexType>::const_iterator polIt;
for ( polIt = resultPolygon.begin(); polIt != resultPolygon.end(); ++polIt)
{
cvf::Trace::show(cvf::String("%1 \t%2 %3 %4").arg((int)(*polIt))
.arg(nodeCoords[*polIt].x())
.arg(nodeCoords[*polIt].y())
.arg(nodeCoords[*polIt].z()));
}
}
#endif
#if DEBUG_PRINT
{
cvf::Trace::show("Connection polygons: ");
for (size_t cIdx = 0; cIdx < faceOverlapPolygons.size(); cIdx++)
{
std::vector<IndexType >::const_iterator polIt;
cvf::Trace::show("Connection " + cvf::String((long long)cIdx));
for (polIt = faceOverlapPolygons[cIdx]->begin(); polIt != faceOverlapPolygons[cIdx]->end(); ++polIt)
{
cvf::Trace::show(cvf::String("%1 \t%2 %3 %4").arg((int)(*polIt))
.arg(nodeCoords[*polIt].x())
.arg(nodeCoords[*polIt].y())
.arg(nodeCoords[*polIt].z()));
}
}
}
#endif
// Merge connection polygons with the main polygon as long as one of them has something in common.
// For each vx in the m_freeFacePolygons[cubeFace] polygon .
// loop over all connections
// if it has the node in common and that the edge angle will decrease if inserting
// merge the connection polygon into the main polygon,
// and remove the connection polygon from the merge able connection polygons.
for (typename std::list<IndexType>::iterator pIt = resultPolygon.begin(); pIt != resultPolygon.end(); ++pIt)
{
// Set iterator to previous node in polygon
typename std::list<IndexType>::iterator prevPIt = pIt;
if (prevPIt == resultPolygon.begin()) prevPIt = resultPolygon.end();
--prevPIt;
cvf::Vec3d pToPrev = nodeCoords[*prevPIt] - nodeCoords[*pIt];
// Set iterator to next node in polygon. Used to insert before and as pointer to the next point
typename std::list<IndexType>::iterator nextPIt = pIt;
++nextPIt;
typename std::list<IndexType>::iterator insertBeforePIt = nextPIt;
if (nextPIt == resultPolygon.end()) nextPIt = resultPolygon.begin();
// Calculate existing edge to edge angle
cvf::Vec3d pToNext = nodeCoords[*nextPIt] - nodeCoords[*pIt];
double mainPolygonEdgeAngle = GeometryTools::getAngle(faceNormal, pToNext , pToPrev);
// Find connections containing the pIt vertex index. Merge them into the main polygon
for (size_t opIdx = 0; opIdx < faceOverlapPolygons.size(); ++opIdx)
{
if (isConnectionPolygonMerged[opIdx]) continue; // Already merged
// Find position of pIt vertex index in the current connection polygon
typename VxIdxToPolygonPositionMap::iterator vxIndexPositionInPolygonIt = polygonSearchMaps[opIdx].find(*pIt);
if (vxIndexPositionInPolygonIt != polygonSearchMaps[opIdx].end())
{
// Merge the connection polygon into the main polygon
// if the angle prevPIt pIt nextPIt is larger than angle prevPIt pIt (startCPIt++)
typename std::vector<IndexType>::const_iterator startCPIt;
startCPIt = vxIndexPositionInPolygonIt->second;
// First vx to insert is the one after the match
bool hasSameWinding = faceOverlapPolygonWindingSameAsCubeFaceFlags[opIdx];
if (hasSameWinding)
{
// Same winding as main polygon. We need to go the opposite way
if (startCPIt == faceOverlapPolygons[opIdx]->begin()) startCPIt = faceOverlapPolygons[opIdx]->end();
--startCPIt;
}
else
{
// Opposite winding. Go forward when merging
++startCPIt; if (startCPIt == faceOverlapPolygons[opIdx]->end()) startCPIt = faceOverlapPolygons[opIdx]->begin();
}
// Calculate possible new edge-to-edge angle and test against existing angle
cvf::Vec3d pToStart = nodeCoords[*startCPIt] - nodeCoords[*pIt];
double candidatePolygonEdgeAngle = GeometryTools::getAngle(faceNormal, pToStart , pToPrev);
if (candidatePolygonEdgeAngle < mainPolygonEdgeAngle )
{
// Merge ok
typename std::vector<IndexType >::const_iterator pcIt = startCPIt;
if (hasSameWinding)
{
do
{
resultPolygon.insert(insertBeforePIt, (*pcIt));
if (pcIt == faceOverlapPolygons[opIdx]->begin()) pcIt = faceOverlapPolygons[opIdx]->end();
--pcIt;
} while (pcIt != startCPIt);
}
else
{
do
{
resultPolygon.insert(insertBeforePIt, (*pcIt));
++pcIt;
if (pcIt == faceOverlapPolygons[opIdx]->end()) pcIt = faceOverlapPolygons[opIdx]->begin();
} while (pcIt != startCPIt);
}
isConnectionPolygonMerged[opIdx] = true;
// Recalculate the next position to point into the new nodes
// Set iterator in the main polygon to insert before and to the next point
nextPIt = pIt;
++nextPIt;
insertBeforePIt = nextPIt;
if (nextPIt == resultPolygon.end()) nextPIt = resultPolygon.begin();
// Recalculate the existing edge to edge angle
pToNext = nodeCoords[*nextPIt] - nodeCoords[*pIt];
mainPolygonEdgeAngle = GeometryTools::getAngle(faceNormal, pToNext , pToPrev);
}
}
}
}
// Now remove all double edges
bool goneAround = false;
for ( typename std::list<IndexType>::iterator pIt = resultPolygon.begin(); pIt != resultPolygon.end() && !goneAround; ++pIt)
{
// Set iterator to next node in polygon.
typename std::list<IndexType>::iterator nextPIt = pIt;
++nextPIt;
if (nextPIt == resultPolygon.end())
{
nextPIt = resultPolygon.begin();
goneAround = true; // Gone around polygon. Stop even if pIt is jumping over end()
}
// Set iterator to previous node in polygon
typename std::list<IndexType>::iterator prevPIt = pIt;
if (prevPIt == resultPolygon.begin()) prevPIt = resultPolygon.end();
--prevPIt;
// If previous and next node are the same, erase
while(*nextPIt == *prevPIt)
{
resultPolygon.erase(pIt);
resultPolygon.erase(prevPIt);
if ( resultPolygon.begin() == resultPolygon.end()) break; // Polygon has been completely removed. Nothing left. Break out of while
pIt = nextPIt;
++nextPIt;
if (nextPIt == resultPolygon.end())
{
nextPIt = resultPolygon.begin();
goneAround = true; // Gone around polygon pIt is jumping over end()
}
prevPIt = pIt;
if (prevPIt == resultPolygon.begin()) prevPIt = resultPolygon.end();
--prevPIt;
}
if ( resultPolygon.begin() == resultPolygon.end()) break; // Polygon has been completely removed. Nothing left. Break out of for loop
}
// Check for holes
bool hasHoles = false;
for (size_t i = 0; i < isConnectionPolygonMerged.size(); ++i)
{
hasHoles = !isConnectionPolygonMerged[i];
if(hasHoles)
{
*m_partiallyFreeCubeFaceHasHoles = true;
break;
}
}
#if DEBUG_PRINT
{
cvf::Trace::show("Polygon: ");
for (std::list<IndexType>::iterator pIt = resultPolygon.begin(); pIt != resultPolygon.end(); ++pIt)
{
cvf::Trace::show(cvf::String("%1 \t%2 %3 %4").arg((int)(*pIt))
.arg(nodeCoords[*pIt].x())
.arg(nodeCoords[*pIt].y())
.arg(nodeCoords[*pIt].z()));
}
}
#endif
// Copy the result polygon to the output variable
partialFacePolygon->clear();
for (typename std::list<IndexType>::iterator pIt = resultPolygon.begin(); pIt != resultPolygon.end(); ++pIt)
{
partialFacePolygon->push_back(*pIt);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename IndexType>
void EdgeIntersectStorage<IndexType>::setVertexCount(size_t size)
{
m_edgeIntsectMap.resize(size);
}
template <typename IndexType>
void EdgeIntersectStorage<IndexType>::canonizeAddress(IndexType& e1P1, IndexType& e1P2, IndexType& e2P1, IndexType& e2P2,
bool& flipE1, bool& flipE2, bool& flipE1E2)
{
flipE1 = e1P1 > e1P2;
flipE2 = e2P1 > e2P2;
flipE1E2 = (flipE1 ? e1P2: e1P1) > (flipE2 ? e2P2: e2P1);
static IndexType temp;
if (flipE1)
{
temp = e1P1;
e1P1 = e1P2;
e1P2 = temp;
}
if (flipE2)
{
temp = e2P1;
e2P1 = e2P2;
e2P2 = temp;
}
if (flipE1E2)
{
temp = e1P1;
e1P1 = e2P1;
e2P1 = temp;
temp = e1P2;
e1P2 = e2P2;
e2P2 = temp;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename IndexType>
void EdgeIntersectStorage<IndexType>::addIntersection(IndexType e1P1, IndexType e1P2, IndexType e2P1, IndexType e2P2,
IndexType vxIndexIntersectionPoint, GeometryTools::IntersectionStatus intersectionStatus,
double fractionAlongEdge1, double fractionAlongEdge2)
{
static bool flipE1 ;
static bool flipE2 ;
static bool flipE1E2;
canonizeAddress(e1P1, e1P2, e2P1, e2P2, flipE1, flipE2, flipE1E2);
static IntersectData iData;
iData.fractionAlongEdge1 = flipE1 ? 1 - fractionAlongEdge1 : fractionAlongEdge1;
iData.fractionAlongEdge2 = flipE2 ? 1 - fractionAlongEdge2 : fractionAlongEdge2;
iData.intersectionStatus = intersectionStatus;
if (flipE1E2)
{
double temp = iData.fractionAlongEdge1;
iData.fractionAlongEdge1 = iData.fractionAlongEdge2;
iData.fractionAlongEdge2 = temp;
}
iData.intersectionPointIndex = vxIndexIntersectionPoint;
CVF_ASSERT(e1P1 < m_edgeIntsectMap.size());
m_edgeIntsectMap[e1P1][e1P2][e2P1][e2P2] = iData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename IndexType>
bool EdgeIntersectStorage<IndexType>::findIntersection(IndexType e1P1, IndexType e1P2, IndexType e2P1, IndexType e2P2,
IndexType* vxIndexIntersectionPoint, GeometryTools::IntersectionStatus* intersectionStatus,
double* fractionAlongEdge1, double* fractionAlongEdge2)
{
static bool flipE1 ;
static bool flipE2 ;
static bool flipE1E2;
canonizeAddress(e1P1, e1P2, e2P1, e2P2, flipE1, flipE2, flipE1E2);
if (!m_edgeIntsectMap[e1P1].size()) return false;
typename std::map<IndexType, std::map<IndexType, std::map<IndexType, IntersectData > > >::iterator it;
it = m_edgeIntsectMap[e1P1].find(e1P2);
if (it == m_edgeIntsectMap[e1P1].end()) return false;
typename std::map<IndexType, std::map<IndexType, IntersectData > >::iterator it2;
it2 = it->second.find(e2P1);
if (it2 == it->second.end()) return false;
typename std::map<IndexType, IntersectData >::iterator it3;
it3 = it2->second.find(e2P2);
if (it3 == it2->second.end()) return false;
*vxIndexIntersectionPoint = it3->second.intersectionPointIndex;
*intersectionStatus = it3->second.intersectionStatus;
if (flipE1E2)
{
*fractionAlongEdge1 = it3->second.fractionAlongEdge2;
*fractionAlongEdge2 = it3->second.fractionAlongEdge1;
}
else
{
*fractionAlongEdge1 = it3->second.fractionAlongEdge1;
*fractionAlongEdge2 = it3->second.fractionAlongEdge2;
}
if (flipE1) *fractionAlongEdge1 = 1 - *fractionAlongEdge1;
if (flipE2) *fractionAlongEdge2 = 1 - *fractionAlongEdge2;
return true;
}
}

View File

@@ -38,9 +38,11 @@
<file>SnapShotSave.png</file>
<file>SnapShotSaveViews.png</file>
<file>draw_style_faults_24x24.png</file>
<file>Case48x48.png</file>
<file>draw_style_faults_label_24x24.png</file>
<file>Case48x48.png</file>
<file>GridModels.png</file>
<file>draw_style_WellCellsToRangeFilter_24x24.png</file>
<file>draw_style_surface_w_fault_mesh_24x24.png</file>
<file>InfoBox16x16.png</file>
</qresource>
<qresource prefix="/Shader/">

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

View File

@@ -49,7 +49,7 @@
#include "cafAnimationToolBar.h"
#include "cafPdmUiPropertyView.h"
#include "cvfqtBasicAboutDialog.h"
#include "cafAboutDialog.h"
#include "cvfTimer.h"
#include "cafPdmFieldCvfMat4d.h"
@@ -295,6 +295,9 @@ void RiuMainWindow::createActions()
//connect(m_drawStyleLinesSolidAction, SIGNAL(triggered()), SLOT(slotDrawStyleLinesSolid()));
m_dsActionGroup->addAction(m_drawStyleLinesSolidAction);
m_drawStyleFaultLinesSolidAction = new QAction(QIcon(":/draw_style_surface_w_fault_mesh_24x24.png"), "Fault Mesh And Surfaces", this);
m_dsActionGroup->addAction(m_drawStyleFaultLinesSolidAction);
m_drawStyleSurfOnlyAction = new QAction(QIcon(":/draw_style_surface_24x24.png"), "&Surface Only", this);
//connect(m_drawStyleSurfOnlyAction, SIGNAL(triggered()), SLOT(slotDrawStyleSurfOnly()));
m_dsActionGroup->addAction(m_drawStyleSurfOnlyAction);
@@ -307,6 +310,10 @@ void RiuMainWindow::createActions()
m_drawStyleToggleFaultsAction->setCheckable(true);
connect(m_drawStyleToggleFaultsAction, SIGNAL(toggled(bool)), SLOT(slotToggleFaultsAction(bool)));
m_toggleFaultsLabelAction = new QAction( QIcon(":/draw_style_faults_label_24x24.png"), "&Show Fault Labels", this);
m_toggleFaultsLabelAction->setCheckable(true);
connect(m_toggleFaultsLabelAction, SIGNAL(toggled(bool)), SLOT(slotToggleFaultLabelsAction(bool)));
m_addWellCellsToRangeFilterAction = new QAction(QIcon(":/draw_style_WellCellsToRangeFilter_24x24.png"), "&Add Well Cells To Range Filter", this);
m_addWellCellsToRangeFilterAction->setCheckable(true);
m_addWellCellsToRangeFilterAction->setToolTip("Add Well Cells To Range Filter based on the individual settings");
@@ -435,7 +442,9 @@ void RiuMainWindow::createToolBars()
m_viewToolBar->addAction(m_drawStyleLinesAction);
m_viewToolBar->addAction(m_drawStyleLinesSolidAction);
m_viewToolBar->addAction(m_drawStyleSurfOnlyAction);
m_viewToolBar->addAction(m_drawStyleFaultLinesSolidAction);
m_viewToolBar->addAction(m_drawStyleToggleFaultsAction);
m_viewToolBar->addAction(m_toggleFaultsLabelAction);
m_viewToolBar->addAction(m_addWellCellsToRangeFilterAction);
QLabel* scaleLabel = new QLabel(m_viewToolBar);
@@ -702,13 +711,12 @@ void RiuMainWindow::refreshAnimationActions()
//--------------------------------------------------------------------------------------------------
void RiuMainWindow::slotAbout()
{
cvfqt::BasicAboutDialog dlg(this);
caf::AboutDialog dlg(this);
dlg.setApplicationName(RI_APPLICATION_NAME);
dlg.setApplicationVersion(RiaApplication::getVersionStringApp(true));
dlg.setCopyright("Copyright 2011-2013 Statoil ASA, Ceetron AS");
dlg.showCeeVizVersion(false);
dlg.showQtVersion(false);
#ifdef _DEBUG
dlg.setIsDebugBuild(true);
#endif
@@ -719,7 +727,7 @@ void RiuMainWindow::slotAbout()
dlg.addVersionEntry(" ", " ");
dlg.addVersionEntry(" ", "Technical Information");
dlg.addVersionEntry(" ", QString(" Qt ") + qVersion());
dlg.addVersionEntry(" ", QString(" ") + dlg.openGLVersionString());
dlg.addVersionEntry(" ", QString(" ") + caf::AboutDialog::versionStringForcurrentOpenGLContext());
dlg.addVersionEntry(" ", caf::Viewer::isShadersSupported() ? " Hardware OpenGL" : " Software OpenGL");
dlg.create();
@@ -806,7 +814,8 @@ void RiuMainWindow::slotOpenProject()
void RiuMainWindow::slotOpenLastUsedProject()
{
RiaApplication* app = RiaApplication::instance();
app->loadLastUsedProject();
QString fileName = app->preferences()->lastUsedProjectFileName;
app->loadProject(fileName);
}
@@ -1396,7 +1405,9 @@ void RiuMainWindow::slotSnapshotAllViewsToFile()
{
RiaApplication* app = RiaApplication::instance();
app->saveSnapshotForAllViews("snapshots");
// Save images in snapshot catalog relative to project directory
QString absolutePathToSnapshotDir = app->createAbsolutePathFromProjectRelativePath("snapshots");
app->saveSnapshotForAllViews(absolutePathToSnapshotDir);
}
//--------------------------------------------------------------------------------------------------
@@ -1471,6 +1482,10 @@ void RiuMainWindow::slotDrawStyleChanged(QAction* activatedAction)
{
RiaApplication::instance()->activeReservoirView()->setSurfOnlyDrawstyle();
}
else if (activatedAction == m_drawStyleFaultLinesSolidAction)
{
RiaApplication::instance()->activeReservoirView()->setFaultMeshSurfDrawstyle();
}
}
@@ -1484,6 +1499,19 @@ void RiuMainWindow::slotToggleFaultsAction(bool showFaults)
RiaApplication::instance()->activeReservoirView()->setShowFaultsOnly(showFaults);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuMainWindow::slotToggleFaultLabelsAction(bool showLabels)
{
if (!RiaApplication::instance()->activeReservoirView()) return;
RiaApplication::instance()->activeReservoirView()->faultCollection->showFaultLabel.setValueFromUi(showLabels);
refreshDrawStyleActions();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -1494,8 +1522,10 @@ void RiuMainWindow::refreshDrawStyleActions()
m_drawStyleLinesAction->setEnabled(enable);
m_drawStyleLinesSolidAction->setEnabled(enable);
m_drawStyleSurfOnlyAction->setEnabled(enable);
m_drawStyleFaultLinesSolidAction->setEnabled(enable);
m_drawStyleToggleFaultsAction->setEnabled(enable);
m_toggleFaultsLabelAction->setEnabled(enable);
m_addWellCellsToRangeFilterAction->setEnabled(enable);
@@ -1503,10 +1533,13 @@ void RiuMainWindow::refreshDrawStyleActions()
{
RimReservoirView* riv = RiaApplication::instance()->activeReservoirView();
m_drawStyleToggleFaultsAction->blockSignals(true);
m_drawStyleToggleFaultsAction->setChecked( riv->meshMode == RimReservoirView::FAULTS_MESH
|| riv->surfaceMode == RimReservoirView::FAULTS);
m_drawStyleToggleFaultsAction->setChecked( !riv->isGridVisualizationMode());
m_drawStyleToggleFaultsAction->blockSignals(false);
m_toggleFaultsLabelAction->blockSignals(true);
m_toggleFaultsLabelAction->setChecked(riv->faultCollection()->showFaultLabel());
m_toggleFaultsLabelAction->blockSignals(false);
m_addWellCellsToRangeFilterAction->blockSignals(true);
m_addWellCellsToRangeFilterAction->setChecked( riv->wellCollection()->wellCellsToRangeFilterMode() != RimWellCollection::RANGE_ADD_NONE);
m_addWellCellsToRangeFilterAction->blockSignals(false);

View File

@@ -96,6 +96,7 @@ public:
void setDefaultWindowSize();
void appendActionsContextMenuForPdmObject(caf::PdmObject* pdmObject, QMenu* menu);
void refreshDrawStyleActions();
protected:
@@ -221,6 +222,8 @@ private slots:
void slotDrawStyleChanged(QAction* activatedAction);
void slotToggleFaultsAction(bool);
void slotToggleFaultLabelsAction(bool);
void slotAddWellCellsToRangeFilterAction(bool doAdd);
// Debug slots
@@ -271,12 +274,13 @@ private:
QActionGroup* m_dsActionGroup;
QAction* m_drawStyleToggleFaultsAction;
QAction* m_toggleFaultsLabelAction;
QAction* m_drawStyleLinesAction;
QAction* m_drawStyleLinesSolidAction;
QAction* m_drawStyleFaultLinesSolidAction;
QAction* m_drawStyleSurfOnlyAction;
QAction* m_addWellCellsToRangeFilterAction;
void refreshDrawStyleActions();
std::vector<QPointer<QDockWidget> > additionalProjectTrees;
std::vector<QPointer<QDockWidget> > additionalPropertyEditors;
};

View File

@@ -46,6 +46,7 @@
#include "cafPdmFieldCvfColor.h"
#include "cafPdmFieldCvfMat4d.h"
#include "RivSourceInfo.h"
using cvf::ManipulatorTrackball;
@@ -70,7 +71,8 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent)
cvf::Font* standardFont = RiaApplication::instance()->standardFont();
cvf::OverlayAxisCross* axisCross = new cvf::OverlayAxisCross(m_mainCamera.p(), standardFont);
axisCross->setAxisLabels("E", "N", "Z");
m_mainRendering->addOverlayItem(axisCross, cvf::OverlayItem::BOTTOM_LEFT, cvf::OverlayItem::VERTICAL);
axisCross->setLayout(cvf::OverlayItem::VERTICAL, cvf::OverlayItem::BOTTOM_LEFT);
m_mainRendering->addOverlayItem(axisCross);
this->enableOverlyPainting(true);
this->setReleaseOGLResourcesEachFrame(true);
@@ -181,12 +183,14 @@ void RiuViewer::updateLegends()
if (m_legend1.notNull())
{
firstRendering->addOverlayItem(m_legend1.p(), cvf::OverlayItem::BOTTOM_LEFT, cvf::OverlayItem::VERTICAL);
m_legend1->setLayout(cvf::OverlayItem::VERTICAL, cvf::OverlayItem::BOTTOM_LEFT);
firstRendering->addOverlayItem(m_legend1.p());
}
if (m_legend2.notNull())
{
firstRendering->addOverlayItem(m_legend2.p(), cvf::OverlayItem::BOTTOM_LEFT, cvf::OverlayItem::VERTICAL);
m_legend2->setLayout(cvf::OverlayItem::VERTICAL, cvf::OverlayItem::BOTTOM_LEFT);
firstRendering->addOverlayItem(m_legend2.p());
}
}
@@ -267,17 +271,20 @@ void RiuViewer::mouseReleaseEvent(QMouseEvent* event)
{
if (firstHitPart->sourceInfo())
{
const cvf::Array<size_t>* cellIndices = dynamic_cast<const cvf::Array<size_t>*>(firstHitPart->sourceInfo());
if (cellIndices)
const RivSourceInfo* rivSourceInfo = dynamic_cast<const RivSourceInfo*>(firstHitPart->sourceInfo());
if (rivSourceInfo)
{
m_currentGridIdx = firstHitPart->id();
m_currentCellIndex = cellIndices->get(faceIndex);
if (rivSourceInfo->hasCellIndices())
{
m_currentGridIdx = firstHitPart->id();
m_currentCellIndex = rivSourceInfo->m_cellIndices->get(faceIndex);
QMenu menu;
menu.addAction(QString("I-slice range filter"), this, SLOT(slotRangeFilterI()));
menu.addAction(QString("J-slice range filter"), this, SLOT(slotRangeFilterJ()));
menu.addAction(QString("K-slice range filter"), this, SLOT(slotRangeFilterK()));
menu.exec(event->globalPos());
QMenu menu;
menu.addAction(QString("I-slice range filter"), this, SLOT(slotRangeFilterI()));
menu.addAction(QString("J-slice range filter"), this, SLOT(slotRangeFilterJ()));
menu.addAction(QString("K-slice range filter"), this, SLOT(slotRangeFilterK()));
menu.exec(event->globalPos());
}
}
}
}
@@ -424,34 +431,46 @@ void RiuViewer::handlePickAction(int winPosX, int winPosY)
{
size_t gridIndex = firstHitPart->id();
size_t cellIndex = cvf::UNDEFINED_SIZE_T;
if (firstHitPart->sourceInfo())
{
const cvf::Array<size_t>* cellIndices = dynamic_cast<const cvf::Array<size_t>*>(firstHitPart->sourceInfo());
if (cellIndices)
const RivSourceInfo* rivSourceInfo = dynamic_cast<const RivSourceInfo*>(firstHitPart->sourceInfo());
if (rivSourceInfo)
{
cellIndex = cellIndices->get(faceIndex);
m_reservoirView->pickInfo(gridIndex, cellIndex, localIntersectionPoint, &pickInfo);
if (isAnimationActive())
if (rivSourceInfo->hasCellIndices())
{
m_reservoirView->appendCellResultInfo(gridIndex, cellIndex, &resultInfo);
}
size_t cellIndex = cvf::UNDEFINED_SIZE_T;
cellIndex = rivSourceInfo->m_cellIndices->get(faceIndex);
CVF_ASSERT(rivSourceInfo->m_faceTypes.notNull());
cvf::StructGridInterface::FaceType face = rivSourceInfo->m_faceTypes->get(faceIndex);
m_reservoirView->pickInfo(gridIndex, cellIndex, face, localIntersectionPoint, &pickInfo);
// Build up result from from both pick info and result values
m_reservoirView->pickInfo(gridIndex, cellIndex, face, localIntersectionPoint, &resultInfo);
resultInfo += "\n";
m_reservoirView->appendCellResultInfo(gridIndex, cellIndex, face, &resultInfo);
#if 0
const RigReservoir* reservoir = m_reservoirView->eclipseCase()->reservoirData();
const RigGridBase* grid = reservoir->grid(gridIndex);
const RigCell& cell = grid->cell(cellIndex);
const caf::SizeTArray8& cellNodeIndices = cell.cornerIndices();
const std::vector<cvf::Vec3d>& nodes = reservoir->mainGrid()->nodes();
for (int i = 0; i < 8; ++i)
{
resultInfo += QString::number(i) + " : ";
for (int j = 0; j < 3; ++j)
resultInfo += QString::number(nodes[cellNodeIndices[i]][j], 'g', 10) + " ";
resultInfo += "\n";
}
const RigCaseData* reservoir = m_reservoirView->eclipseCase()->reservoirData();
const RigGridBase* grid = reservoir->grid(gridIndex);
const RigCell& cell = grid->cell(cellIndex);
const caf::SizeTArray8& cellNodeIndices = cell.cornerIndices();
const std::vector<cvf::Vec3d>& nodes = reservoir->mainGrid()->nodes();
for (int i = 0; i < 8; ++i)
{
resultInfo += QString::number(i) + " : ";
for (int j = 0; j < 3; ++j)
resultInfo += QString::number(nodes[cellNodeIndices[i]][j], 'g', 10) + " ";
resultInfo += "\n";
}
#endif
}
else if (rivSourceInfo->m_NNCIndices.notNull())
{
size_t nncIndex = rivSourceInfo->m_NNCIndices->get(faceIndex);
m_reservoirView->appendNNCResultInfo(nncIndex, &resultInfo);
}
}
}
}
@@ -534,18 +553,46 @@ cvf::Part* RiuViewer::pickPointAndFace(int winPosX, int winPosY, uint* faceHit,
{
CVF_ASSERT(faceHit);
cvf::HitItemCollection pPoints;
bool isSomethingHit = rayPick(winPosX, winPosY, &pPoints);
cvf::HitItemCollection hitItems;
bool isSomethingHit = rayPick(winPosX, winPosY, &hitItems);
if (isSomethingHit)
{
CVF_ASSERT(pPoints.count() > 0);
cvf::HitItem* firstItem = pPoints.firstItem();
const cvf::Part* pickedPart = firstItem->part();
CVF_ASSERT(hitItems.count() > 0);
double characteristicCellSize = m_reservoirView->eclipseCase()->reservoirData()->mainGrid()->characteristicIJCellSize();
double pickDepthThresholdSquared = characteristicCellSize / 100.0;
pickDepthThresholdSquared = pickDepthThresholdSquared * pickDepthThresholdSquared;
cvf::HitItem* hitItem = hitItems.firstItem();
cvf::Vec3d firstItemIntersectionPoint = hitItem->intersectionPoint();
// Check if we have a close hit item with NNC data
for (size_t i = 0; i < hitItems.count(); i++)
{
cvf::HitItem* hitItemCandidate = hitItems.item(i);
cvf::Vec3d diff = firstItemIntersectionPoint - hitItemCandidate->intersectionPoint();
// Hit items are ordered by distance from eye
if (diff.lengthSquared() > pickDepthThresholdSquared) break;
const cvf::Part* pickedPartCandidate = hitItemCandidate->part();
if (pickedPartCandidate && pickedPartCandidate->sourceInfo())
{
const RivSourceInfo* rivSourceInfo = dynamic_cast<const RivSourceInfo*>(pickedPartCandidate->sourceInfo());
if (rivSourceInfo && rivSourceInfo->hasNNCIndices())
{
hitItem = hitItemCandidate;
break;
}
}
}
const cvf::Part* pickedPart = hitItem->part();
CVF_ASSERT(pickedPart);
const cvf::Transform* xf = pickedPart->transform();
cvf::Vec3d globalPickedPoint = firstItem->intersectionPoint();
cvf::Vec3d globalPickedPoint = hitItem->intersectionPoint();
if(localIntersectionPoint)
{
@@ -562,7 +609,7 @@ cvf::Part* RiuViewer::pickPointAndFace(int winPosX, int winPosY, uint* faceHit,
if (faceHit)
{
const cvf::HitDetailDrawableGeo* detail = dynamic_cast<const cvf::HitDetailDrawableGeo*>(firstItem->detail());
const cvf::HitDetailDrawableGeo* detail = dynamic_cast<const cvf::HitDetailDrawableGeo*>(hitItem->detail());
if (detail)
{
*faceHit = detail->faceIndex();

View File

@@ -0,0 +1,48 @@
[ Contents ](UsersGuide.md#contents)
------
## Batch Commands
ResInsight supports several commands useful in a batch setting. These examples are available from the [test section](https://github.com/OPM/ResInsight/tree/master/TestModels/Case_with_10_timesteps).
See also [ Command Line Arguments](CommandLineParameters.md) for an overview of all command line arguments.
### Example 1 : Create snapshots of all views for multiple cases
A list of cases is defined in **CaseList.txt**, containing the following
Real0/BRUGGE_0000.EGRID
Real10/BRUGGE_0010.EGRID
Real30/BRUGGE_0030.EGRID
Real40/BRUGGE_0040.EGRID
The command line used to run this example is shown here:
ResInsight --project BatchTest.rsp --multiCaseSnapshots CaseList.txt --size 500 500
This will instruct ResInsight to read the project file **BatchTest.rsp**. All cases will be replaced one by one in ResInsight, and snapshots of all views will be written to file.
### Example 2 : Replace a single case and take snapshots of all views
The command line used to run this example is shown here:
ResInsight --project BatchTest.rsp --replaceCase "Real10\BRUGGE_0010.EGRID" --savesnapshots
This will instruct ResInsight to read the project file **BatchTest.rsp**. The specified case **Real10\BRUGGE_0010.EGRID** will be imported into the project, and snapshots of all views will be written to file.
### Example 3 : Replace source cases in a case group and create snapshot
A list of cases is defined in **CaseList2.txt**, containing the following
Real0/BRUGGE_0000.EGRID
Real10/BRUGGE_0010.EGRID
The command line used to run this example is shown here:
ResInsight --project BatchStatistics.rsp --replaceSourceCases CaseList2.txt --savesnapshots
This will instruct ResInsight to read the project file **BatchTest.rsp**. All cases specified will be imported in the case group specified in the project file. Statistics will be computed, and snapshots for all views will be written to file.
------
[ Contents ](UsersGuide.md#contents)

View File

@@ -5,13 +5,18 @@
| Parameter | Description |
|-----------|-------------|
| `-help, -?` | Displays help text and version info |
| `-last` | Open last used project |
| `-project <filename>` | Open project file <filename> |
| `-case <casename>` | Import Eclipse case <casename> (do not include .GRID/.EGRID) |
| `-savesnapshots` | Save snapshot of all views to 'snapshots' folder in project file folder. Application closes after snapshots are written to file. |
| `-regressiontest <folder>` | Run a regression test on all sub-folders starting with `TestCase*` of the given folder. **RegressionTest.rip** files in the sub-folders will be opened and snapshots of all the views is written to the sub-sub-folder **RegTestGeneratedImages**. Then difference images is generated in the sub-sub-folder **RegTestDiffImages** based on the images in sub-sub-folder **RegTestBaseImages**. The results are presented in **ResInsightRegressionTestReport.html** that is written in the given folder. |
| `-updateregressiontestbase <folder>` | For all sub-folders starting with `TestCase*`, copy the images in the sub-sub-folder **RegTestGeneratedImages** to the sub-sub-folder **RegTestBaseImages** after deleting **RegTestBaseImages** completely. |
| `--last` | Open last used project. |
| `--project <filename>` | Open project file <filename>. |
| `--case <casename>` | Import Eclipse case <casename> (do not include .GRID/.EGRID) |
| `--startdir <folder>` | Set startup directory. |
| `--savesnapshots` | Save snapshot of all views to 'snapshots' folder in project file folder. Application closes after snapshots have been written. |
| `--size <width> <height>` | Set size of the main application window. |
| `--replaceCase [<caseId>] <newGridFile>` | Replace grid in <caseId> or first case with <newgridFile>. |
| `--replaceSourceCases [<caseGroupId>] <gridListFile>` | Replace source cases in <caseGroupId> or first grid case group with the grid files listed in the <gridListFile> file. |
| `--multiCaseSnapshots <gridListFile>` | For each grid file listed in the <gridListFile> file, replace the first case in the project and save snapshot of all views. |
| `--help, -?` | Displays help text and version info |
| `--regressiontest <folder>` | Run a regression test on all sub-folders starting with `TestCase*` of the given folder. **RegressionTest.rip** files in the sub-folders will be opened and snapshots of all the views is written to the sub-sub-folder **RegTestGeneratedImages**. Then difference images is generated in the sub-sub-folder **RegTestDiffImages** based on the images in sub-sub-folder **RegTestBaseImages**. The results are presented in **ResInsightRegressionTestReport.html** that is written in the given folder. |
| `--updateregressiontestbase <folder>` | For all sub-folders starting with `TestCase*`, copy the images in the sub-sub-folder **RegTestGeneratedImages** to the sub-sub-folder **RegTestBaseImages** after deleting **RegTestBaseImages** completely. |
See also the [Regression Test System ](RegressionTestSystem.md) for a more in-depth explanation.

View File

@@ -0,0 +1,44 @@
[ Contents ](UsersGuide.md#contents)
-----
## 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.
As import of faults can be time consuming, reading of faults can be disabled from **Preferences -> Read fault data**
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**.
When clicking on a NNC, the relevant data for this NNC is displayed in the **Result Info**. The static result **CombindedTRANS** can be mapped onto NNC geometry.
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 **Unnamed grid faults**.
### 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
### Common Fault Options
By clicking the ![](images/draw_style_faults_24x24.png) **Faults** item in the **Project Tree**, the following options are displayed:
![](images/FaultProperties.png)
- **Show defined faces**: Displays the defined fault cell faces
- **Show opposite faces**: Displays the opposite fault cell faces based on IJK neighbor data
- **Show NNCs**: Displays non neighborhood connections (see details below)
- **Dynamic Face Selection**: Controls mapping of cell results onto a fault, either from cell in front of fault, from cell behind fault or both.
- **Show labels**: Displays one label per fault with fault name
- **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.
------
[ Contents ](UsersGuide.md#contents)

View File

@@ -26,4 +26,3 @@ Currently tested and verified version on Windows is Octave 3.6.1. NB! Version 3.
------
[ Contents ](UsersGuide.md#contents)

View File

@@ -12,3 +12,62 @@ Pandoc can be used to generated PDF from a markdown file like this
See here for information on Pandoc
[http://johnmacfarlane.net/pandoc/](http://johnmacfarlane.net/pandoc/)
## Internal documentation notes
### Produce PDF from markup - 28. oct 2013
The documentation for Git is build using a set of markup files. Below is a set of command history on Ubuntu 13.04 to be able to produce PDF from markup.
NOTE: On Ubuntu, use the following fonts in latex/config.yml
Ubuntu for normal text and DejaVu Sans Mono for monospace.
https://github.com/progit/progit/issues/11
16 cd ..
17 git clone https://github.com/progit/progit.git
18 cd progit/
19 ls
20 ./makepdfs en
21 sudo apt-get install ruby
22 ./makepdfs en
23 sudo apt-get install pandoc
24 ./makepdfs en
25 sudo apt-get install xelatex
26 sudo apt-get install texlive-xetex
27 ./makepdfs en
28 dir
29 sudo apt-get install texlive
30 ./makepdfs en
31 sudo apt-get install texlive-latex-extra
32 sudo apt-get install texlive-latex-base
33 ./makepdfs en
34 sudo apt-get install texlive-latex-extra
35 ./makepdfs en
36 ls
37 cd latex/
38 ls
39 kate config.yml
40 sudo apt-get install kate
41 kedit config.yml
42 gedit config.yml
43*
44 cd ..
45 ls
46 ./makepdfs en
47 fc-match helvetica
48 ./makepdfs en
49 fc-list
50 fc-match helvetica
51 fc-match helvetica neue
52 ./makepdfs en
53 fc-list
54 ./makepdfs en
55 ./makepdfs en --debug
56 ./makepdfs en
57 ls
58 ./progit.en.pdf
59 evince
60 history

View File

@@ -20,6 +20,8 @@ ResInsight has been co-developed by Statoil ASA, Ceetron Solutions AS, and Ceetr
- [ Multiple realizations and statistics ](CaseGroupsAndStatistics.md)
- [ Octave Interface](OctaveInterface.md)
- [ Well Trajectories ](WellPaths.md)
- [ Faults ](Faults.md)
- [ Batch Commands ](BatchCommands.md)
### Appendix

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

16
Fwk/AppFwk/CMakeLists.txt Normal file
View File

@@ -0,0 +1,16 @@
cmake_minimum_required (VERSION 2.8)
project (CeeApp)
find_package (Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED)
include (${QT_USE_FILE})
#libraries
add_subdirectory(cafProjectDataModel)
add_subdirectory(cafUserInterface)
#executables
add_subdirectory(cafTests/cafProjectDataModel_UnitTests)
add_subdirectory(cafTests/cafTestApplication)

View File

@@ -24,6 +24,8 @@ add_library( ${PROJECT_NAME}
cafUtils.h
cvfStructGrid.cpp
cvfStructGrid.h
cvfCellRange.cpp
cvfCellRange.h
cvfStructGridGeometryGenerator.cpp

View File

@@ -104,6 +104,34 @@ cvf::String CommonShaderSources::light_AmbientDiffuse()
//--------------------------------------------------------------------------------------------------
/// Static helper to configure polygon offset render state from enum
//--------------------------------------------------------------------------------------------------
static cvf::ref<cvf::RenderStatePolygonOffset> CreateAngConfigurePolygonOffsetRenderState(PolygonOffset polygonOffset)
{
cvf::ref<cvf::RenderStatePolygonOffset> rs = new cvf::RenderStatePolygonOffset;
if (polygonOffset == PO_NONE)
{
return rs;
}
rs->enableFillMode(true);
switch (polygonOffset)
{
case PO_1: rs->setFactor(1.0f); rs->setUnits(1.0f); break;
case PO_2: rs->setFactor(2.0f); rs->setUnits(2.0f); break;
case PO_NEG_LARGE: rs->setFactor(-1.0f); rs->setUnits(-30.0f); break;
default:
CVF_FAIL_MSG("Unhandled polygon offset enum");
}
return rs;
}
//==================================================================================================
//
// EffectGenerator Base class
@@ -205,21 +233,23 @@ void EffectGenerator::releaseUnreferencedEffects()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
SurfaceEffectGenerator::SurfaceEffectGenerator(const cvf::Color4f& color, bool polygonOffset)
SurfaceEffectGenerator::SurfaceEffectGenerator(const cvf::Color4f& color, PolygonOffset polygonOffset)
{
m_color = color;
m_polygonOffset = polygonOffset;
m_cullBackfaces = false;
m_cullBackfaces = FC_NONE;
m_enableDepthWrite = true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
SurfaceEffectGenerator::SurfaceEffectGenerator(const cvf::Color3f& color, bool polygonOffset)
SurfaceEffectGenerator::SurfaceEffectGenerator(const cvf::Color3f& color, PolygonOffset polygonOffset)
{
m_color = cvf::Color4f(color, 1.0f);
m_polygonOffset = polygonOffset;
m_cullBackfaces = false;
m_cullBackfaces = FC_NONE;
m_enableDepthWrite = true;
}
@@ -269,10 +299,9 @@ void SurfaceEffectGenerator::updateForFixedFunctionRendering(cvf::Effect* effect
//--------------------------------------------------------------------------------------------------
void SurfaceEffectGenerator::updateCommonEffect(cvf::Effect* effect) const
{
if (m_polygonOffset)
if (m_polygonOffset != PO_NONE)
{
cvf::ref<cvf::RenderStatePolygonOffset> polyOffset = new cvf::RenderStatePolygonOffset;
polyOffset->configurePolygonPositiveOffset();
cvf::ref<cvf::RenderStatePolygonOffset> polyOffset = CreateAngConfigurePolygonOffsetRenderState(m_polygonOffset);
effect->setRenderState(polyOffset.p());
}
@@ -284,13 +313,32 @@ void SurfaceEffectGenerator::updateCommonEffect(cvf::Effect* effect) const
effect->setRenderState(blender.p());
}
// Backface culling
if (m_cullBackfaces)
// Face culling
if (m_cullBackfaces != FC_NONE)
{
cvf::ref<cvf::RenderStateCullFace> faceCulling = new cvf::RenderStateCullFace;
if (m_cullBackfaces == FC_BACK)
{
faceCulling->setMode(cvf::RenderStateCullFace::BACK);
}
else if (m_cullBackfaces == FC_FRONT)
{
faceCulling->setMode(cvf::RenderStateCullFace::FRONT);
}
else if (m_cullBackfaces == FC_FRONT_AND_BACK)
{
faceCulling->setMode(cvf::RenderStateCullFace::FRONT_AND_BACK);
}
effect->setRenderState(faceCulling.p());
}
if (!m_enableDepthWrite)
{
cvf::ref<cvf::RenderStateDepth> depth = new cvf::RenderStateDepth;
depth->enableDepthWrite(false);
effect->setRenderState(depth.p());
}
}
//--------------------------------------------------------------------------------------------------
@@ -304,6 +352,7 @@ bool SurfaceEffectGenerator::isEqual(const EffectGenerator* other) const
{
if (m_color == otherSurfaceEffect->m_color
&& m_polygonOffset == otherSurfaceEffect->m_polygonOffset
&& m_enableDepthWrite == otherSurfaceEffect->m_enableDepthWrite
&& m_cullBackfaces == otherSurfaceEffect->m_cullBackfaces)
{
return true;
@@ -320,6 +369,7 @@ EffectGenerator* SurfaceEffectGenerator::copy() const
{
SurfaceEffectGenerator* effGen = new SurfaceEffectGenerator(m_color, m_polygonOffset);
effGen->m_cullBackfaces = m_cullBackfaces;
effGen->m_enableDepthWrite = m_enableDepthWrite;
return effGen;
}
@@ -337,13 +387,14 @@ EffectGenerator* SurfaceEffectGenerator::copy() const
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ScalarMapperEffectGenerator::ScalarMapperEffectGenerator(const cvf::ScalarMapper* scalarMapper, bool polygonOffset)
ScalarMapperEffectGenerator::ScalarMapperEffectGenerator(const cvf::ScalarMapper* scalarMapper, PolygonOffset polygonOffset)
: m_undefinedColor(cvf::Color3::GRAY)
{
m_scalarMapper = scalarMapper;
m_polygonOffset = polygonOffset;
m_opacityLevel = 1.0f;
m_cullBackfaces = false;
m_faceCulling = FC_NONE;
m_enableDepthWrite = true;
}
//--------------------------------------------------------------------------------------------------
@@ -426,10 +477,9 @@ void ScalarMapperEffectGenerator::updateCommonEffect(cvf::Effect* effect) const
{
CVF_ASSERT(effect);
if (m_polygonOffset)
if (m_polygonOffset != PO_NONE)
{
cvf::ref<cvf::RenderStatePolygonOffset> polyOffset = new cvf::RenderStatePolygonOffset;
polyOffset->configurePolygonPositiveOffset();
cvf::ref<cvf::RenderStatePolygonOffset> polyOffset = CreateAngConfigurePolygonOffsetRenderState(m_polygonOffset);
effect->setRenderState(polyOffset.p());
}
@@ -442,12 +492,31 @@ void ScalarMapperEffectGenerator::updateCommonEffect(cvf::Effect* effect) const
}
// Backface culling
if (m_cullBackfaces)
if (m_faceCulling != FC_NONE)
{
cvf::ref<cvf::RenderStateCullFace> faceCulling = new cvf::RenderStateCullFace;
if (m_faceCulling == FC_BACK)
{
faceCulling->setMode(cvf::RenderStateCullFace::BACK);
}
else if (m_faceCulling == FC_FRONT)
{
faceCulling->setMode(cvf::RenderStateCullFace::FRONT);
}
else if (m_faceCulling == FC_FRONT_AND_BACK)
{
faceCulling->setMode(cvf::RenderStateCullFace::FRONT_AND_BACK);
}
effect->setRenderState(faceCulling.p());
}
if (!m_enableDepthWrite)
{
cvf::ref<cvf::RenderStateDepth> depth = new cvf::RenderStateDepth;
depth->enableDepthWrite(false);
effect->setRenderState(depth.p());
}
}
@@ -464,7 +533,8 @@ bool ScalarMapperEffectGenerator::isEqual(const EffectGenerator* other) const
&& m_polygonOffset == otherTextureResultEffect->m_polygonOffset
&& m_opacityLevel == otherTextureResultEffect->m_opacityLevel
&& m_undefinedColor == otherTextureResultEffect->m_undefinedColor
&& m_cullBackfaces == otherTextureResultEffect->m_cullBackfaces)
&& m_faceCulling == otherTextureResultEffect->m_faceCulling
&& m_enableDepthWrite == otherTextureResultEffect->m_enableDepthWrite)
{
cvf::ref<cvf::TextureImage> texImg2 = new cvf::TextureImage;
otherTextureResultEffect->m_scalarMapper->updateTexture(texImg2.p());
@@ -485,7 +555,8 @@ EffectGenerator* ScalarMapperEffectGenerator::copy() const
scEffGen->m_textureImage = m_textureImage;
scEffGen->m_opacityLevel = m_opacityLevel;
scEffGen->m_undefinedColor = m_undefinedColor;
scEffGen->m_cullBackfaces = m_cullBackfaces;
scEffGen->m_faceCulling = m_faceCulling;
scEffGen->m_enableDepthWrite = m_enableDepthWrite;
return scEffGen;
}

Some files were not shown because too many files have changed in this diff Show More