Fishbones : Add model and visualization

This commit is contained in:
Magne Sjaastad 2017-05-05 11:21:40 +02:00
parent 2dcf3c75f5
commit 414733899e
19 changed files with 1167 additions and 7 deletions

View File

@ -49,6 +49,7 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel
${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Summary
${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Flow
${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Fishbones
${CMAKE_CURRENT_SOURCE_DIR}/ResultStatisticsCache
${CMAKE_CURRENT_SOURCE_DIR}/ReservoirDataModel
@ -107,6 +108,7 @@ list( APPEND REFERENCED_CMAKE_FILES
ProjectDataModel/CMakeLists_files.cmake
ProjectDataModel/Summary/CMakeLists_files.cmake
ProjectDataModel/Flow/CMakeLists_files.cmake
ProjectDataModel/Fishbones/CMakeLists_files.cmake
GeoMech/GeoMechVisualization/CMakeLists_files.cmake
@ -121,6 +123,7 @@ list( APPEND REFERENCED_CMAKE_FILES
Commands/CrossSectionCommands/CMakeLists_files.cmake
Commands/EclipseCommands/CMakeLists_files.cmake
Commands/EclipseCommands/EclipseWell/CMakeLists_files.cmake
Commands/FishbonesCommands/CMakeLists_files.cmake
Commands/FlowCommands/CMakeLists_files.cmake
Commands/IntersectionBoxCommands/CMakeLists_files.cmake
Commands/OctaveScriptCommands/CMakeLists_files.cmake

View File

@ -0,0 +1,23 @@
# Use this workaround until we're on 2.8.3 on all platforms and can use CMAKE_CURRENT_LIST_DIR directly
if (${CMAKE_VERSION} VERSION_GREATER "2.8.2")
set(CEE_CURRENT_LIST_DIR ${CMAKE_CURRENT_LIST_DIR}/)
endif()
set (SOURCE_GROUP_HEADER_FILES
${CEE_CURRENT_LIST_DIR}RicNewFishbonesSubsFeature.h
)
set (SOURCE_GROUP_SOURCE_FILES
${CEE_CURRENT_LIST_DIR}RicNewFishbonesSubsFeature.cpp
)
list(APPEND CODE_HEADER_FILES
${SOURCE_GROUP_HEADER_FILES}
)
list(APPEND CODE_SOURCE_FILES
${SOURCE_GROUP_SOURCE_FILES}
)
source_group( "CommandFeature\\Fishbones" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CEE_CURRENT_LIST_DIR}CMakeLists_files.cmake )

View File

@ -0,0 +1,87 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicNewFishbonesSubsFeature.h"
#include "RimFishbonesMultipleSubs.h"
#include "RimWellPath.h"
#include "RiuMainWindow.h"
#include "cafSelectionManager.h"
#include <QAction>
CAF_CMD_SOURCE_INIT(RicNewFishbonesSubsFeature, "RicNewFishbonesSubsFeature");
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewFishbonesSubsFeature::onActionTriggered(bool isChecked)
{
RimWellPath* wellPath = selectedWellPath();
CVF_ASSERT(wellPath);
RimFishbonesMultipleSubs* obj = new RimFishbonesMultipleSubs;
obj->setName(QString("Fishbones Subs (%1)").arg(wellPath->fishbonesSubs.size()));
wellPath->fishbonesSubs.push_back(obj);
wellPath->updateConnectedEditors();
RiuMainWindow::instance()->selectAsCurrentItem(obj);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimWellPath* RicNewFishbonesSubsFeature::selectedWellPath()
{
RimWellPath* wellPath = nullptr;
caf::PdmUiItem* pdmUiItem = caf::SelectionManager::instance()->selectedItem();
caf::PdmObjectHandle* objHandle = dynamic_cast<caf::PdmObjectHandle*>(pdmUiItem);
if (objHandle)
{
objHandle->firstAncestorOrThisOfType(wellPath);
}
return wellPath;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewFishbonesSubsFeature::setupActionLook(QAction* actionToSetup)
{
//actionToSetup->setIcon(QIcon(":/FractureSymbol16x16.png"));
actionToSetup->setText("New Fishbones Subs Definition");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicNewFishbonesSubsFeature::isCommandEnabled()
{
if (selectedWellPath())
{
return true;
}
return false;
}

View File

@ -0,0 +1,39 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
class RimWellPath;
//==================================================================================================
///
//==================================================================================================
class RicNewFishbonesSubsFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
protected:
virtual void onActionTriggered(bool isChecked) override;
virtual void setupActionLook(QAction* actionToSetup) override;
virtual bool isCommandEnabled() override;
private:
static RimWellPath* selectedWellPath();
};

View File

@ -25,6 +25,7 @@
#include "RimEclipseInputProperty.h"
#include "RimEclipsePropertyFilter.h"
#include "RimEclipseView.h"
#include "RimFishbonesMultipleSubs.h"
#include "RimFormationNames.h"
#include "RimFormationNamesCollection.h"
#include "RimGeoMechPropertyFilter.h"
@ -92,6 +93,7 @@ bool isDeletable(PdmUiItem * uiItem)
if (dynamic_cast<RimIntersectionBox*>(uiItem)) return true;
if (dynamic_cast<RimFormationNames*>(uiItem)) return true;
if (dynamic_cast<RimFormationNamesCollection*>(uiItem)) return true;
if (dynamic_cast<RimFishbonesMultipleSubs*>(uiItem)) return true;
return false;
}

View File

@ -35,9 +35,11 @@ ${CEE_CURRENT_LIST_DIR}RivSingleCellPartGenerator.h
${CEE_CURRENT_LIST_DIR}RivSimWellPipeSourceInfo.h
${CEE_CURRENT_LIST_DIR}RivWellSpheresPartMgr.h
${CEE_CURRENT_LIST_DIR}RivPartPriority.h
${CEE_CURRENT_LIST_DIR}RivWellConnectionsPartMgr.h
${CEE_CURRENT_LIST_DIR}RivObjectSourceInfo.h
${CEE_CURRENT_LIST_DIR}RivWellConnectionsPartMgr.h
${CEE_CURRENT_LIST_DIR}RivObjectSourceInfo.h
${CEE_CURRENT_LIST_DIR}RivFishbonesSubsPartMgr.h
)
set (SOURCE_GROUP_SOURCE_FILES
@ -68,8 +70,11 @@ ${CEE_CURRENT_LIST_DIR}RivPipeQuadToSegmentMapper.cpp
${CEE_CURRENT_LIST_DIR}RivSingleCellPartGenerator.cpp
${CEE_CURRENT_LIST_DIR}RivSimWellPipeSourceInfo.cpp
${CEE_CURRENT_LIST_DIR}RivWellSpheresPartMgr.cpp
${CEE_CURRENT_LIST_DIR}RivWellConnectionsPartMgr.cpp
${CEE_CURRENT_LIST_DIR}RivObjectSourceInfo.cpp
${CEE_CURRENT_LIST_DIR}RivWellConnectionsPartMgr.cpp
${CEE_CURRENT_LIST_DIR}RivObjectSourceInfo.cpp
${CEE_CURRENT_LIST_DIR}RivFishbonesSubsPartMgr.cpp
)
list(APPEND CODE_HEADER_FILES

View File

@ -0,0 +1,233 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RivFishbonesSubsPartMgr.h"
#include "RigWellPath.h"
#include "RimFishbonesMultipleSubs.h"
#include "RimWellPath.h"
#include "RivObjectSourceInfo.h"
#include "RivPipeGeometryGenerator.h"
#include "cafDisplayCoordTransform.h"
#include "cafEffectGenerator.h"
#include "cvfDrawableGeo.h"
#include "cvfModelBasicList.h"
#include "cvfPart.h"
#include "cvfTransform.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivFishbonesSubsPartMgr::RivFishbonesSubsPartMgr(RimFishbonesMultipleSubs* subs)
: m_rimFishbonesSubs(subs)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivFishbonesSubsPartMgr::~RivFishbonesSubsPartMgr()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFishbonesSubsPartMgr::appendGeometryPartsToModel(cvf::ModelBasicList* model, caf::DisplayCoordTransform* displayCoordTransform, double characteristicCellSize)
{
clearGeometryCache();
if (!m_rimFishbonesSubs->isChecked()) return;
if (m_parts.size() == 0)
{
buildParts(displayCoordTransform, characteristicCellSize);
}
for (auto part : m_parts)
{
model->addPart(part.p());
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFishbonesSubsPartMgr::clearGeometryCache()
{
m_parts.clear();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFishbonesSubsPartMgr::buildParts(caf::DisplayCoordTransform* displayCoordTransform, double characteristicCellSize)
{
std::vector<double> locationOfSubs = m_rimFishbonesSubs->locationOfSubs();
RimWellPath* wellPath = nullptr;
m_rimFishbonesSubs->firstAncestorOrThisOfTypeAsserted(wellPath);
RigWellPath* rigWellPath = wellPath->wellPathGeometry();
RivPipeGeometryGenerator geoGenerator;
geoGenerator.setRadius(m_rimFishbonesSubs->tubingRadius());
for (size_t instanceIndex = 0; instanceIndex < locationOfSubs.size(); instanceIndex++)
{
double measuredDepth = locationOfSubs[instanceIndex];
cvf::Vec3d position = rigWellPath->interpolatedPointAlongWellPath(measuredDepth);
cvf::Vec3d p1 = cvf::Vec3d::UNDEFINED;
cvf::Vec3d p2 = cvf::Vec3d::UNDEFINED;
rigWellPath->twoClosestPoints(position, &p1, &p2);
if (!p1.isUndefined() && !p2.isUndefined())
{
std::vector<double> lateralLengths = m_rimFishbonesSubs->lateralLengths();
cvf::Mat4d buildAngleRotationMatrix;
for (size_t i = 0; i < lateralLengths.size(); i++)
{
cvf::Vec3d lateralDirection;
{
cvf::Vec3d alongWellPath = (p2 - p1).getNormalized();
cvf::Vec3d lateralInitialDirection = cvf::Vec3d::Z_AXIS;
{
double intialRotationAngle = m_rimFishbonesSubs->rotationAngle(instanceIndex);
double lateralOffsetDegrees = 360.0 / lateralLengths.size();
double lateralOffsetRadians = cvf::Math::toRadians(intialRotationAngle + lateralOffsetDegrees * i);
cvf::Mat4d lateralOffsetMatrix = cvf::Mat4d::fromRotation(alongWellPath, lateralOffsetRadians);
lateralInitialDirection = lateralInitialDirection.getTransformedVector(lateralOffsetMatrix);
}
cvf::Vec3d rotationAxis;
rotationAxis.cross(alongWellPath, lateralInitialDirection);
double exitAngleRadians = cvf::Math::toRadians(m_rimFishbonesSubs->exitAngle());
cvf::Mat4d lateralRotationMatrix = cvf::Mat4d::fromRotation(rotationAxis, exitAngleRadians);
lateralDirection = alongWellPath.getTransformedVector(lateralRotationMatrix);
double buildAngleRadians = cvf::Math::toRadians(m_rimFishbonesSubs->buildAngle());
buildAngleRotationMatrix = cvf::Mat4d::fromRotation(rotationAxis, buildAngleRadians);
}
std::vector<cvf::Vec3d> domainCoords;
// Compute coordinates along the lateral by modifying the lateral direction by the build angle for
// every unit vector along the lateral
{
cvf::Vec3d accumulatedPosition = position;
double accumulatedLength = 0.0;
while (accumulatedLength < lateralLengths[i])
{
domainCoords.push_back(accumulatedPosition);
double delta = 1.0;
if (lateralLengths[i] - accumulatedLength < 1.0)
{
delta = lateralLengths[i] - accumulatedLength;
}
accumulatedPosition += delta * lateralDirection;
// Modify the lateral direction by the build angle for each unit vector
lateralDirection = lateralDirection.getTransformedVector(buildAngleRotationMatrix);
accumulatedLength += delta;
}
// Add the last accumulated position if it is not present
if (domainCoords.back() != accumulatedPosition)
{
domainCoords.push_back(accumulatedPosition);
}
}
std::vector<cvf::Vec3d> displayCoords;
for (auto domainCoord : domainCoords)
{
displayCoords.push_back(displayCoordTransform->transformToDisplayCoord(domainCoord));
}
cylinderWithCenterLineParts(&m_parts, displayCoords, wellPath->wellPathColor(), wellPath->combinedScaleFactor() * characteristicCellSize * 0.5);
cvf::ref<RivObjectSourceInfo> objectSourceInfo = new RivObjectSourceInfo(m_rimFishbonesSubs);
for (auto p : m_parts)
{
p->setSourceInfo(objectSourceInfo.p());
}
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivFishbonesSubsPartMgr::cylinderWithCenterLineParts(cvf::Collection<cvf::Part>* destinationParts, const std::vector<cvf::Vec3d>& centerCoords, const cvf::Color3f& color, double radius)
{
cvf::ref<RivPipeGeometryGenerator> geoGenerator = new RivPipeGeometryGenerator;
geoGenerator->setRadius(radius);
geoGenerator->setCrossSectionVertexCount(12);
cvf::ref<cvf::Vec3dArray> cvfCoords = new cvf::Vec3dArray(centerCoords);
geoGenerator->setPipeCenterCoords(cvfCoords.p());
cvf::ref<cvf::DrawableGeo> surfaceGeo = geoGenerator->createPipeSurface();
if (surfaceGeo.notNull())
{
cvf::Part* part = new cvf::Part;
part->setDrawable(surfaceGeo.p());
caf::SurfaceEffectGenerator surfaceGen(cvf::Color4f(color), caf::PO_1);
cvf::ref<cvf::Effect> eff = surfaceGen.generateCachedEffect();
part->setEffect(eff.p());
destinationParts->push_back(part);
}
cvf::ref<cvf::DrawableGeo> centerLineGeo = geoGenerator->createCenterLine();
if (centerLineGeo.notNull())
{
cvf::Part* part = new cvf::Part;
part->setDrawable(centerLineGeo.p());
caf::SurfaceEffectGenerator surfaceGen(cvf::Color4f(color), caf::PO_1);
cvf::ref<cvf::Effect> eff = surfaceGen.generateCachedEffect();
part->setEffect(eff.p());
destinationParts->push_back(part);
}
}

View File

@ -0,0 +1,67 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmPointer.h"
#include "cvfBase.h"
#include "cvfMatrix4.h"
#include "cvfObject.h"
#include "cvfVector3.h"
#include "cvfCollection.h"
#include "cvfColor3.h"
namespace cvf
{
class ModelBasicList;
class DrawableGeo;
class Part;
class Transform;
}
namespace caf
{
class DisplayCoordTransform;
}
class RimFishbonesMultipleSubs;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
class RivFishbonesSubsPartMgr : public cvf::Object
{
public:
RivFishbonesSubsPartMgr(RimFishbonesMultipleSubs* subs);
~RivFishbonesSubsPartMgr();
void appendGeometryPartsToModel(cvf::ModelBasicList* model, caf::DisplayCoordTransform* displayCoordTransform, double characteristicCellSize);
void clearGeometryCache();
private:
void buildParts(caf::DisplayCoordTransform* displayCoordTransform, double characteristicCellSize);
static void cylinderWithCenterLineParts(cvf::Collection<cvf::Part>* destinationParts, const std::vector<cvf::Vec3d>& centerCoords, const cvf::Color3f& color, double radius);
private:
caf::PdmPointer<RimFishbonesMultipleSubs> m_rimFishbonesSubs;
cvf::Collection<cvf::Part> m_parts;
};

View File

@ -351,4 +351,4 @@ cvf::ref< cvf::DrawableGeo> RivWellConnectionsPartMgr::createArrowGeometry(const
geo->computeNormals();
return geo;
}
}

View File

@ -25,10 +25,11 @@
#include "RigWellPath.h"
#include "RimFishbonesMultipleSubs.h"
#include "RimWellPath.h"
#include "RimWellPathCollection.h"
#include "RivPipeGeometryGenerator.h"
#include "RivFishbonesSubsPartMgr.h"
#include "RivPartPriority.h"
#include "RivPipeGeometryGenerator.h"
#include "RivWellPathSourceInfo.h"
@ -83,6 +84,31 @@ RivWellPathPartMgr::~RivWellPathPartMgr()
clearAllBranchData();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivWellPathPartMgr::appendFishbonesPartsToModel(cvf::ModelBasicList* model, caf::DisplayCoordTransform* displayCoordTransform, double characteristicCellSize)
{
if (!m_rimWellPath) return;
// This concept is taken from RivReservoirSimWellsPartMgr, and is required to be able to have
// separate part managers for each view
if (m_fishbonesPartMgrs.size() != m_rimWellPath->fishbonesSubs().size())
{
m_fishbonesPartMgrs.clear();
for (auto rimFishboneSubs : m_rimWellPath->fishbonesSubs())
{
m_fishbonesPartMgrs.push_back(new RivFishbonesSubsPartMgr(rimFishboneSubs));
}
}
for (auto rivFishbonesPartManager : m_fishbonesPartMgrs)
{
rivFishbonesPartManager->appendGeometryPartsToModel(model, displayCoordTransform, characteristicCellSize);
}
}
//--------------------------------------------------------------------------------------------------
/// The pipe geometry needs to be rebuilt on scale change to keep the pipes round
//--------------------------------------------------------------------------------------------------
@ -268,6 +294,8 @@ void RivWellPathPartMgr::appendStaticGeometryPartsToModel(cvf::ModelBasicList* m
{
model->addPart(m_wellLabelPart.p());
}
appendFishbonesPartsToModel(model, displayCoordTransform, characteristicCellSize);
}
//--------------------------------------------------------------------------------------------------
@ -282,6 +310,16 @@ void RivWellPathPartMgr::setScaleTransform( cvf::Transform * scaleTransform )
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivWellPathPartMgr::scheduleGeometryRegen()
{
m_needsTransformUpdate = true;
m_fishbonesPartMgrs.clear();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -22,6 +22,7 @@
#include "cafPdmPointer.h"
#include "cvfBoundingBox.h"
#include "cvfCollection.h"
namespace cvf
{
@ -40,6 +41,7 @@ namespace caf {
class RivPipeGeometryGenerator;
class RimProject;
class RimWellPath;
class RivFishbonesSubsPartMgr;
class RivWellPathPartMgr : public cvf::Object
{
@ -49,7 +51,7 @@ public:
void setScaleTransform(cvf::Transform * scaleTransform);
void scheduleGeometryRegen() { m_needsTransformUpdate = true; }//printf("R"); }
void scheduleGeometryRegen();
void appendStaticGeometryPartsToModel(cvf::ModelBasicList* model, cvf::Vec3d displayModelOffset,
double characteristicCellSize, cvf::BoundingBox wellPathClipBoundingBox,
@ -57,14 +59,17 @@ public:
size_t segmentIndexFromTriangleIndex(size_t triangleIndex);
private:
void appendFishbonesPartsToModel(cvf::ModelBasicList* model, caf::DisplayCoordTransform* displayCoordTransform, double characteristicCellSize);
void buildWellPathParts(cvf::Vec3d displayModelOffset, double characteristicCellSize, cvf::BoundingBox wellPathClipBoundingBox);
void clearAllBranchData();
private:
caf::PdmPointer<RimWellPath> m_rimWellPath;
cvf::ref<cvf::Transform> m_scaleTransform;
bool m_needsTransformUpdate;
void buildWellPathParts(cvf::Vec3d displayModelOffset, double characteristicCellSize, cvf::BoundingBox wellPathClipBoundingBox);
void clearAllBranchData();
struct RivPipeBranchData
{
cvf::ref<RivPipeGeometryGenerator> m_pipeGeomGenerator;
@ -80,4 +85,6 @@ private:
cvf::ref<cvf::ScalarMapper> m_scalarMapper;
cvf::ref<cvf::Effect> m_scalarMapperSurfaceEffect;
cvf::ref<cvf::Effect> m_scalarMapperMeshEffect;
cvf::Collection<RivFishbonesSubsPartMgr> m_fishbonesPartMgrs;
};

View File

@ -0,0 +1,23 @@
# Use this workaround until we're on 2.8.3 on all platforms and can use CMAKE_CURRENT_LIST_DIR directly
if (${CMAKE_VERSION} VERSION_GREATER "2.8.2")
set(CEE_CURRENT_LIST_DIR ${CMAKE_CURRENT_LIST_DIR}/)
endif()
set (SOURCE_GROUP_HEADER_FILES
${CEE_CURRENT_LIST_DIR}RimFishbonesMultipleSubs.h
)
set (SOURCE_GROUP_SOURCE_FILES
${CEE_CURRENT_LIST_DIR}RimFishbonesMultipleSubs.cpp
)
list(APPEND CODE_HEADER_FILES
${SOURCE_GROUP_HEADER_FILES}
)
list(APPEND CODE_SOURCE_FILES
${SOURCE_GROUP_SOURCE_FILES}
)
source_group( "ProjectDataModel\\Fishbones" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CEE_CURRENT_LIST_DIR}CMakeLists_files.cmake )

View File

@ -0,0 +1,396 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimFishbonesMultipleSubs.h"
#include "RimProject.h"
#include "cafPdmUiListEditor.h"
#include "cvfAssert.h"
#include <iostream>
#include <ctime>
#include <cstdlib>
CAF_PDM_SOURCE_INIT(RimFishbonesMultipleSubs, "FishbonesMultipleSubs");
namespace caf {
template<>
void AppEnum<RimFishbonesMultipleSubs::LocationType>::setUp()
{
addItem(RimFishbonesMultipleSubs::FB_SUB_COUNT_END, "FB_SUB_COUNT", "Start/End/Count");
addItem(RimFishbonesMultipleSubs::FB_SUB_SPACING_END, "FB_SUB_SPACING", "Start/End/Spacing");
addItem(RimFishbonesMultipleSubs::FB_SUB_USER_DEFINED, "FB_SUB_CUSTOM", "User Specification");
setDefault(RimFishbonesMultipleSubs::FB_SUB_USER_DEFINED);
}
template<>
void AppEnum<RimFishbonesMultipleSubs::LateralsOrientationType>::setUp()
{
addItem(RimFishbonesMultipleSubs::FB_LATERAL_ORIENTATION_FIXED, "FB_LATERAL_ORIENTATION_FIXED", "Fixed Angle");
addItem(RimFishbonesMultipleSubs::FB_LATERAL_ORIENTATION_RANDOM, "FB_LATERAL_ORIENTATION_RANDOM", "Random Angle");
setDefault(RimFishbonesMultipleSubs::FB_LATERAL_ORIENTATION_RANDOM);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFishbonesMultipleSubs::RimFishbonesMultipleSubs()
{
CAF_PDM_InitObject("FishbonesMultipleSubs", ":/Default.png", "", "");
CAF_PDM_InitField(&m_lateralCountPerSub, "LateralCountPerSub", size_t(3), "Count Per Sub", "", "", "");
CAF_PDM_InitField(&m_lateralLength, "LateralLength", QString("12.0"), "Length(s) [m]", "", "Specify multiple length values if the sub lengths differ", "");
CAF_PDM_InitField(&m_lateralExitAngle, "LateralExitAngle", 35.0, "Exit Angle [deg]", "", "", "");
CAF_PDM_InitField(&m_lateralBuildAngle, "LateralBuildAngle", 5.0, "Build Angle [deg/m]", "", "", "");
CAF_PDM_InitField(&m_lateralHoleRadius, "LateralHoleRadius", 12.0, "Hole Radius [mm]", "", "", "");
CAF_PDM_InitField(&m_lateralTubingRadius, "LateralTubingRadius", 8.0, "Tubing Radius [mm]", "", "", "");
CAF_PDM_InitField(&m_lateralOpenHoleRoghnessFactor, "LateralOpenHoleRoghnessFactor", 0.001, "Open Hole Roghness Factor [m]", "", "", "");
CAF_PDM_InitField(&m_lateralTubingRoghnessFactor, "LateralTubingRoghnessFactor", 1e-5, "Tubing Roghness Factor [m]", "", "", "");
CAF_PDM_InitField(&m_lateralLengthFraction, "LateralLengthFraction", 100.0, "Length Fraction [0..1]", "", "", "");
CAF_PDM_InitField(&m_lateralInstallFraction, "LateralInstallFraction", 100.0, "Install Fraction [0..1]", "", "", "");
CAF_PDM_InitField(&m_icdCount, "IcdCount", size_t(2), "ICD Count", "", "", "");
CAF_PDM_InitField(&m_icdOrificeRadius, "IcdOrificeRadius", 8.0, "ICD Orifice Radius [mm]", "", "", "");
CAF_PDM_InitFieldNoDefault(&m_locationOfSubs, "LocationOfSubs", "Measured Depths [m]", "", "", "");
m_locationOfSubs.uiCapability()->setUiEditorTypeName(caf::PdmUiListEditor::uiEditorTypeName());
CAF_PDM_InitField(&m_subsLocationMode, "SubsLocationMode", caf::AppEnum<LocationType>(FB_SUB_USER_DEFINED), "Location Defined By", "", "", "");
CAF_PDM_InitField(&m_rangeStart, "RangeStart", 100.0, "Start [m]", "", "", "");
CAF_PDM_InitField(&m_rangeEnd, "RangeEnd", 250.0, "End [m]", "", "", "");
CAF_PDM_InitField(&m_rangeSubSpacing, "RangeSubSpacing", 40.0, "Spacing [m]", "", "", "");
CAF_PDM_InitField(&m_rangeSubCount, "RangeSubCount", size_t(25), "Count", "", "", "");
CAF_PDM_InitField(&m_subsOrientationMode, "SubsOrientationMode", caf::AppEnum<LateralsOrientationType>(FB_LATERAL_ORIENTATION_RANDOM), "Orientation", "", "", "");
CAF_PDM_InitFieldNoDefault(&m_installationRotationAngles, "InstallationRotationAngles", "Installation Rotation Angles [deg]", "", "", "");
m_installationRotationAngles.uiCapability()->setUiHidden(true);
CAF_PDM_InitField(&m_fixedInstallationRotationAngle, "FixedInstallationRotationAngle", 0.0, " Fixed Angle [deg]", "", "", "");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFishbonesMultipleSubs::~RimFishbonesMultipleSubs()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimFishbonesMultipleSubs::locationOfSubs() const
{
return m_locationOfSubs;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimFishbonesMultipleSubs::rotationAngle(size_t index) const
{
if (m_subsOrientationMode == FB_LATERAL_ORIENTATION_FIXED)
{
return m_fixedInstallationRotationAngle;
}
else
{
CVF_ASSERT(index < m_installationRotationAngles().size());
return m_installationRotationAngles()[index];
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimFishbonesMultipleSubs::exitAngle() const
{
return m_lateralExitAngle;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimFishbonesMultipleSubs::buildAngle() const
{
return m_lateralBuildAngle;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimFishbonesMultipleSubs::tubingRadius() const
{
return m_lateralTubingRadius;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimFishbonesMultipleSubs::lateralCountPerSub() const
{
return m_lateralCountPerSub;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimFishbonesMultipleSubs::lateralLengths() const
{
QStringList items = m_lateralLength().split(' ');
double currentLength = 0.0;
std::vector<double> lengths;
for (int i = 0; i < static_cast<int>(m_lateralCountPerSub); i++)
{
if (i < items.size())
{
bool conversionOk = false;
double candidateValue = items[i].toDouble(&conversionOk);
if (conversionOk)
{
currentLength = candidateValue;
}
}
lengths.push_back(currentLength);
}
return lengths;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFishbonesMultipleSubs::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue)
{
bool recomputeLocations = false;
if (changedField == &m_subsLocationMode)
{
if (m_subsLocationMode == FB_SUB_COUNT_END || m_subsLocationMode == FB_SUB_SPACING_END)
{
recomputeLocations = true;
}
}
if (changedField == &m_rangeStart ||
changedField == &m_rangeEnd ||
changedField == &m_rangeSubCount ||
changedField == &m_rangeSubSpacing)
{
recomputeLocations = true;
}
if (recomputeLocations)
{
if (m_subsLocationMode == FB_SUB_COUNT_END)
{
size_t divisor = 1;
if (m_rangeSubCount > 2) divisor = m_rangeSubCount - 1;
m_rangeSubSpacing = fabs(m_rangeStart - m_rangeEnd) / divisor;
}
else if (m_subsLocationMode == FB_SUB_SPACING_END)
{
m_rangeSubCount = (fabs(m_rangeStart - m_rangeEnd) / m_rangeSubSpacing) + 1;
if (m_rangeSubCount < 1)
{
m_rangeSubCount = 1;
}
}
if (m_subsLocationMode == FB_SUB_COUNT_END || m_subsLocationMode == FB_SUB_SPACING_END)
{
std::vector<double> measuredDepths = locationsFromStartSpacingAndCount(m_rangeStart, m_rangeSubSpacing, m_rangeSubCount);
m_locationOfSubs = measuredDepths;
}
}
if (recomputeLocations ||
changedField == &m_locationOfSubs ||
changedField == &m_subsOrientationMode)
{
m_installationRotationAngles.v().clear();
recomputeIntallationRotationAngles();
}
RimProject* proj;
this->firstAncestorOrThisOfTypeAsserted(proj);
proj->createDisplayModelAndRedrawAllViews();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFishbonesMultipleSubs::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering)
{
uiOrdering.add(&m_name); // From RimNamedObject
{
caf::PdmUiGroup* group = uiOrdering.addNewGroup("Location");
group->add(&m_subsLocationMode);
if (m_subsLocationMode() != FB_SUB_USER_DEFINED)
{
group->add(&m_rangeStart);
group->add(&m_rangeEnd);
if (m_subsLocationMode() == FB_SUB_COUNT_END)
{
group->add(&m_rangeSubCount);
group->add(&m_rangeSubSpacing);
}
else if (m_subsLocationMode() == FB_SUB_SPACING_END)
{
group->add(&m_rangeSubSpacing);
group->add(&m_rangeSubCount);
}
}
group->add(&m_locationOfSubs);
}
{
caf::PdmUiGroup* group = uiOrdering.addNewGroup("Lateral Configuration");
group->add(&m_lateralCountPerSub);
group->add(&m_lateralLength);
group->add(&m_lateralExitAngle);
group->add(&m_lateralBuildAngle);
group->add(&m_subsOrientationMode);
if (m_subsOrientationMode == FB_LATERAL_ORIENTATION_FIXED)
{
group->add(&m_fixedInstallationRotationAngle);
}
caf::PdmUiGroup* successGroup = group->addNewGroup("Installation Success Factors");
successGroup->add(&m_lateralLengthFraction);
successGroup->add(&m_lateralInstallFraction);
caf::PdmUiGroup* mswGroup = group->addNewGroup("Multi Segment Wells");
mswGroup->setCollapsedByDefault(true);
mswGroup->add(&m_lateralHoleRadius);
mswGroup->add(&m_lateralTubingRadius);
mswGroup->add(&m_lateralOpenHoleRoghnessFactor);
mswGroup->add(&m_lateralTubingRoghnessFactor);
mswGroup->add(&m_icdCount);
mswGroup->add(&m_icdOrificeRadius);
}
// Visibility
if (m_subsLocationMode == FB_SUB_USER_DEFINED)
{
m_locationOfSubs.uiCapability()->setUiReadOnly(false);
m_rangeSubSpacing.uiCapability()->setUiReadOnly(true);
m_rangeSubCount.uiCapability()->setUiReadOnly(true);
m_rangeStart.uiCapability()->setUiReadOnly(true);
m_rangeEnd.uiCapability()->setUiReadOnly(true);
}
else
{
m_locationOfSubs.uiCapability()->setUiReadOnly(true);
m_rangeSubSpacing.uiCapability()->setUiReadOnly(false);
m_rangeSubCount.uiCapability()->setUiReadOnly(false);
m_rangeStart.uiCapability()->setUiReadOnly(false);
m_rangeEnd.uiCapability()->setUiReadOnly(false);
if (m_subsLocationMode == FB_SUB_COUNT_END)
{
m_rangeSubSpacing.uiCapability()->setUiReadOnly(true);
m_rangeSubCount.uiCapability()->setUiReadOnly(false);
}
else
{
m_rangeSubSpacing.uiCapability()->setUiReadOnly(false);
m_rangeSubCount.uiCapability()->setUiReadOnly(true);
}
}
uiOrdering.skipRemainingFields();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFishbonesMultipleSubs::initAfterRead()
{
if (m_locationOfSubs().size() != m_installationRotationAngles().size())
{
recomputeIntallationRotationAngles();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFishbonesMultipleSubs::recomputeIntallationRotationAngles()
{
std::vector<double> vals;
for (size_t i = 0; i < m_locationOfSubs().size(); i++)
{
vals.push_back(RimFishbonesMultipleSubs::randomValue(0, 360));
}
m_installationRotationAngles = vals;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimFishbonesMultipleSubs::locationsFromStartSpacingAndCount(double start, double spacing, size_t count)
{
std::vector<double> measuredDepths;
for (size_t i = 0; i < count; i++)
{
measuredDepths.push_back(start + spacing * i);
}
return measuredDepths;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RimFishbonesMultipleSubs::randomValue(int min, int max)
{
int range = abs(max - min);
int random_integer = min + int(range*rand() / (RAND_MAX + 1.0));
return random_integer;
}

View File

@ -0,0 +1,106 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimCheckableNamedObject.h"
//==================================================================================================
///
///
//==================================================================================================
class RimFishbonesMultipleSubs : public RimCheckableNamedObject
{
CAF_PDM_HEADER_INIT;
public:
enum LocationType
{
FB_SUB_COUNT_END,
FB_SUB_SPACING_END,
FB_SUB_USER_DEFINED
};
enum LateralsOrientationType
{
FB_LATERAL_ORIENTATION_FIXED,
FB_LATERAL_ORIENTATION_RANDOM
};
public:
RimFishbonesMultipleSubs();
virtual ~RimFishbonesMultipleSubs();
std::vector<double> locationOfSubs() const;
double rotationAngle(size_t index) const;
double exitAngle() const;
double buildAngle() const;
double tubingRadius() const;
double lateralCountPerSub() const;
std::vector<double> lateralLengths() const;
virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override;
protected:
virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override;
virtual void initAfterRead() override;
private:
void recomputeIntallationRotationAngles();
static std::vector<double> locationsFromStartSpacingAndCount(double start, double spacing, size_t count);
static int randomValue(int min, int max);
private:
caf::PdmField<size_t> m_lateralCountPerSub;
caf::PdmField<QString> m_lateralLength;
caf::PdmField<double> m_lateralExitAngle;
caf::PdmField<double> m_lateralBuildAngle;
caf::PdmField<double> m_lateralHoleRadius;
caf::PdmField<double> m_lateralTubingRadius;
caf::PdmField<double> m_lateralOpenHoleRoghnessFactor;
caf::PdmField<double> m_lateralTubingRoghnessFactor;
caf::PdmField<double> m_lateralLengthFraction;
caf::PdmField<double> m_lateralInstallFraction;
caf::PdmField<size_t> m_icdCount;
caf::PdmField<double> m_icdOrificeRadius;
caf::PdmField<caf::AppEnum<LocationType> > m_subsLocationMode;
caf::PdmField<double> m_rangeStart;
caf::PdmField<double> m_rangeEnd;
caf::PdmField<double> m_rangeSubSpacing;
caf::PdmField<size_t> m_rangeSubCount;
caf::PdmField<caf::AppEnum<LateralsOrientationType> > m_subsOrientationMode;
caf::PdmField<std::vector<double>> m_locationOfSubs; // Given in measured depth
caf::PdmField<std::vector<double>> m_installationRotationAngles;
caf::PdmField<double> m_fixedInstallationRotationAngle;
};

View File

@ -394,6 +394,8 @@ QStringList RimContextCommandBuilder::commandsFromSelection()
commandIds << "RicShowTotalAllocationDataFeature";
commandIds << "RicSummaryCurveSwitchAxisFeature";
commandIds << "RicNewFishbonesSubsFeature";
// Work in progress -- End

View File

@ -32,6 +32,8 @@
#include "RimWellLogPlotCollection.h"
#include "RimWellPathCollection.h"
#include "RimFishbonesMultipleSubs.h"
#include "RiuMainWindow.h"
#include "RivWellPathPartMgr.h"
@ -101,6 +103,9 @@ RimWellPath::RimWellPath()
CAF_PDM_InitFieldNoDefault(&m_wellLogFile, "WellLogFile", "Well Log File", "", "", "");
m_wellLogFile.uiCapability()->setUiHidden(true);
CAF_PDM_InitFieldNoDefault(&fishbonesSubs, "FishbonesSubs", "fishbonesSubs", "", "", "");
fishbonesSubs.uiCapability()->setUiHidden(true);
m_wellPath = NULL;
}
@ -421,6 +426,17 @@ void RimWellPath::updateFilePathsFromProjectPath(const QString& newProjectPath,
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimWellPath::combinedScaleFactor() const
{
RimWellPathCollection* wellPathColl = nullptr;
this->firstAncestorOrThisOfTypeAsserted(wellPathColl);
return this->wellPathRadiusScaleFactor() * wellPathColl->wellPathRadiusScaleFactor();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -29,6 +29,7 @@
// Include to make Pdm work for cvf::Color
#include "cafPdmFieldCvfColor.h"
#include "cafPdmChildArrayField.h"
#include "cvfObject.h"
class RifWellPathAsciiFileReader;
@ -37,6 +38,8 @@ class RimProject;
class RimWellLogFile;
class RivWellPathPartMgr;
class RimFishbonesMultipleSubs;
//==================================================================================================
///
///
@ -70,12 +73,14 @@ public:
caf::PdmChildField<RimWellLogFile*> m_wellLogFile;
RigWellPath* wellPathGeometry();
caf::PdmChildArrayField<RimFishbonesMultipleSubs*> fishbonesSubs;
RivWellPathPartMgr* partMgr();
bool readWellPathFile(QString * errorMessage, RifWellPathAsciiFileReader* asciiReader);
void updateFilePathsFromProjectPath(const QString& newProjectPath, const QString& oldProjectPath);
double combinedScaleFactor() const;
private:

View File

@ -18,6 +18,8 @@
#include "RigWellPath.h"
#include "cvfGeometryTools.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -52,3 +54,106 @@ double RigWellPath::datumElevation() const
return m_datumElevation;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Vec3d RigWellPath::interpolatedPointAlongWellPath(double measuredDepth)
{
cvf::Vec3d wellPathPoint = cvf::Vec3d::ZERO;
size_t i = 0;
while (i < m_measuredDepths.size() && m_measuredDepths.at(i) < measuredDepth )
{
i++;
}
if (m_measuredDepths.size() > i)
{
if (i == 0)
{
//For measuredDepth same or lower than first point, use this first point
wellPathPoint = m_wellPathPoints.at(0);
}
else
{
//Do interpolation
double stepsize = (measuredDepth - m_measuredDepths.at(i-1)) /
(m_measuredDepths.at(i) - m_measuredDepths.at(i - 1));
wellPathPoint = m_wellPathPoints.at(i - 1) + stepsize * (m_wellPathPoints.at(i) - m_wellPathPoints.at(i-1));
}
}
else
{
//Use endpoint if measuredDepth same or higher than last point
wellPathPoint = m_wellPathPoints.at(i-1);
}
return wellPathPoint;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigWellPath::wellPathAzimuthAngle(const cvf::Vec3d& position) const
{
double azimuthAngle = 0.0;
cvf::Vec3d p1 = cvf::Vec3d::UNDEFINED;
cvf::Vec3d p2 = cvf::Vec3d::UNDEFINED;
twoClosestPoints(position, &p1, &p2);
if (!p1.isUndefined() && !p2.isUndefined())
{
cvf::Vec3d direction = p1 - p2;
if (abs(direction.x()) > 1e-5)
{
double atanValue = direction.y() / direction.x();
azimuthAngle = atan(atanValue);
azimuthAngle = cvf::Math::toDegrees(azimuthAngle);
azimuthAngle = -azimuthAngle;
}
}
return azimuthAngle;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigWellPath::twoClosestPoints(const cvf::Vec3d& position, cvf::Vec3d* p1, cvf::Vec3d* p2) const
{
CVF_ASSERT(p1 && p2);
size_t closestIndex = cvf::UNDEFINED_SIZE_T;
double closestDistance = cvf::UNDEFINED_DOUBLE;
for (size_t i = 1; i < m_wellPathPoints.size(); i++)
{
cvf::Vec3d p1 = m_wellPathPoints[i - 1];
cvf::Vec3d p2 = m_wellPathPoints[i - 0];
double candidateDistance = cvf::GeometryTools::linePointSquareDist(p1, p2, position);
if (candidateDistance < closestDistance)
{
closestDistance = candidateDistance;
closestIndex = i;
}
}
if (closestIndex != cvf::UNDEFINED_DOUBLE)
{
if (closestIndex > 0)
{
*p1 = m_wellPathPoints[closestIndex - 1];
*p2 = m_wellPathPoints[closestIndex - 0];
}
else
{
*p1 = m_wellPathPoints[closestIndex + 1];
*p2 = m_wellPathPoints[closestIndex + 0];
}
}
}

View File

@ -40,6 +40,9 @@ public:
void setDatumElevation(double value);
bool hasDatumElevation() const;
double datumElevation() const;
cvf::Vec3d interpolatedPointAlongWellPath(double measuredDepth);
double wellPathAzimuthAngle(const cvf::Vec3d& position) const;
void twoClosestPoints(const cvf::Vec3d& position, cvf::Vec3d* p1, cvf::Vec3d* p2) const;
private:
bool m_hasDatumElevation;