mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
32
.gitignore
vendored
32
.gitignore
vendored
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
255
ApplicationCode/Application/RiaProjectModifier.cpp
Normal file
255
ApplicationCode/Application/RiaProjectModifier.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
62
ApplicationCode/Application/RiaProjectModifier.h
Normal file
62
ApplicationCode/Application/RiaProjectModifier.h
Normal 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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
43
ApplicationCode/ModelVisualization/RivColorTableArray.cpp
Normal file
43
ApplicationCode/ModelVisualization/RivColorTableArray.cpp
Normal 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;
|
||||
}
|
||||
|
||||
29
ApplicationCode/ModelVisualization/RivColorTableArray.h
Normal file
29
ApplicationCode/ModelVisualization/RivColorTableArray.h
Normal 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();
|
||||
};
|
||||
287
ApplicationCode/ModelVisualization/RivFaultGeometryGenerator.cpp
Normal file
287
ApplicationCode/ModelVisualization/RivFaultGeometryGenerator.cpp
Normal 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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
728
ApplicationCode/ModelVisualization/RivFaultPartMgr.cpp
Normal file
728
ApplicationCode/ModelVisualization/RivFaultPartMgr.cpp
Normal 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());
|
||||
}
|
||||
}
|
||||
|
||||
107
ApplicationCode/ModelVisualization/RivFaultPartMgr.h
Normal file
107
ApplicationCode/ModelVisualization/RivFaultPartMgr.h
Normal 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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
191
ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.cpp
Normal file
191
ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.cpp
Normal 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;
|
||||
}
|
||||
|
||||
70
ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.h
Normal file
70
ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.h
Normal 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;
|
||||
};
|
||||
235
ApplicationCode/ModelVisualization/RivReservoirFaultsPartMgr.cpp
Normal file
235
ApplicationCode/ModelVisualization/RivReservoirFaultsPartMgr.cpp
Normal 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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
36
ApplicationCode/ModelVisualization/RivSourceInfo.cpp
Normal file
36
ApplicationCode/ModelVisualization/RivSourceInfo.cpp
Normal 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();
|
||||
}
|
||||
37
ApplicationCode/ModelVisualization/RivSourceInfo.h
Normal file
37
ApplicationCode/ModelVisualization/RivSourceInfo.h
Normal 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;
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -40,5 +40,8 @@ public:
|
||||
};
|
||||
|
||||
static QString undefinedResultName() { return "None"; }
|
||||
static QString undefinedGridFaultName() { return "Undefined grid faults"; }
|
||||
|
||||
static QString combinedTransmissibilityResultName() { return "TRANSXYZ"; }
|
||||
};
|
||||
|
||||
|
||||
122
ApplicationCode/ProjectDataModel/RimFault.cpp
Normal file
122
ApplicationCode/ProjectDataModel/RimFault.cpp
Normal 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;
|
||||
}
|
||||
|
||||
59
ApplicationCode/ProjectDataModel/RimFault.h
Normal file
59
ApplicationCode/ProjectDataModel/RimFault.h
Normal 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;
|
||||
};
|
||||
287
ApplicationCode/ProjectDataModel/RimFaultCollection.cpp
Normal file
287
ApplicationCode/ProjectDataModel/RimFaultCollection.cpp
Normal 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);
|
||||
}
|
||||
|
||||
88
ApplicationCode/ProjectDataModel/RimFaultCollection.h
Normal file
88
ApplicationCode/ProjectDataModel/RimFaultCollection.h
Normal 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;
|
||||
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -40,6 +40,7 @@ public:
|
||||
RimResultCase();
|
||||
virtual ~RimResultCase();
|
||||
|
||||
void setGridFileName(const QString& caseFileName);
|
||||
void setCaseInfo(const QString& userDescription, const QString& caseFileName);
|
||||
|
||||
virtual bool openEclipseGridFile();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -964,10 +964,16 @@ void RimUiTreeView::slotComputeStatistics()
|
||||
|
||||
statisticsCase->computeStatistics();
|
||||
|
||||
statisticsCase->scheduleACTIVEGeometryRegenOnReservoirViews();
|
||||
statisticsCase->updateConnectedEditorsAndReservoirViews();
|
||||
|
||||
if (statisticsCase->reservoirViews.size() == 0)
|
||||
{
|
||||
slotAddView();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]];
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
154
ApplicationCode/ReservoirDataModel/RigFault.cpp
Normal file
154
ApplicationCode/ReservoirDataModel/RigFault.cpp
Normal 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);
|
||||
|
||||
}
|
||||
}
|
||||
109
ApplicationCode/ReservoirDataModel/RigFault.h
Normal file
109
ApplicationCode/ReservoirDataModel/RigFault.h
Normal 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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
180
ApplicationCode/ReservoirDataModel/RigNNCData.cpp
Normal file
180
ApplicationCode/ReservoirDataModel/RigNNCData.cpp
Normal 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;
|
||||
}
|
||||
*/
|
||||
72
ApplicationCode/ReservoirDataModel/RigNNCData.h
Normal file
72
ApplicationCode/ReservoirDataModel/RigNNCData.h
Normal 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;
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
925
ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp
Normal file
925
ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
167
ApplicationCode/ReservoirDataModel/cvfGeometryTools.h
Normal file
167
ApplicationCode/ReservoirDataModel/cvfGeometryTools.h
Normal 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"
|
||||
957
ApplicationCode/ReservoirDataModel/cvfGeometryTools.inl
Normal file
957
ApplicationCode/ReservoirDataModel/cvfGeometryTools.inl
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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/">
|
||||
|
||||
BIN
ApplicationCode/Resources/draw_style_faults_label_24x24.png
Normal file
BIN
ApplicationCode/Resources/draw_style_faults_label_24x24.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 886 B |
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
48
Documentation/UsersGuide/BatchCommands.md
Normal file
48
Documentation/UsersGuide/BatchCommands.md
Normal 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)
|
||||
@@ -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.
|
||||
|
||||
|
||||
44
Documentation/UsersGuide/Faults.md
Normal file
44
Documentation/UsersGuide/Faults.md
Normal file
@@ -0,0 +1,44 @@
|
||||
[ Contents ](UsersGuide.md#contents)
|
||||
|
||||
-----
|
||||
## Faults
|
||||
|
||||
ResInsight can import faults from `*.DATA` files, and is available in the  **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.
|
||||
|
||||
-  Toggle button to control faults only visualization mode
|
||||
-  Shows surface visualization
|
||||
-  Shows mesh lines on faults
|
||||
|
||||
|
||||
### Common Fault Options
|
||||
By clicking the  **Faults** item in the **Project Tree**, the following options are displayed:
|
||||
|
||||

|
||||
|
||||
|
||||
- **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)
|
||||
|
||||
|
||||
@@ -26,4 +26,3 @@ Currently tested and verified version on Windows is Octave 3.6.1. NB! Version 3.
|
||||
|
||||
------
|
||||
[ Contents ](UsersGuide.md#contents)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
BIN
Documentation/UsersGuide/images/FaultProperties.png
Normal file
BIN
Documentation/UsersGuide/images/FaultProperties.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 317 KiB |
BIN
Documentation/UsersGuide/images/draw_style_faults_24x24.png
Normal file
BIN
Documentation/UsersGuide/images/draw_style_faults_24x24.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Documentation/UsersGuide/images/draw_style_surface_24x24.png
Normal file
BIN
Documentation/UsersGuide/images/draw_style_surface_24x24.png
Normal file
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
16
Fwk/AppFwk/CMakeLists.txt
Normal 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)
|
||||
|
||||
@@ -24,6 +24,8 @@ add_library( ${PROJECT_NAME}
|
||||
cafUtils.h
|
||||
cvfStructGrid.cpp
|
||||
cvfStructGrid.h
|
||||
cvfCellRange.cpp
|
||||
cvfCellRange.h
|
||||
|
||||
|
||||
cvfStructGridGeometryGenerator.cpp
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user