diff --git a/ApplicationLibCode/Commands/WellPathCommands/RicDuplicateWellPathFeature.cpp b/ApplicationLibCode/Commands/WellPathCommands/RicDuplicateWellPathFeature.cpp index 4d200bb220..b9826622f3 100644 --- a/ApplicationLibCode/Commands/WellPathCommands/RicDuplicateWellPathFeature.cpp +++ b/ApplicationLibCode/Commands/WellPathCommands/RicDuplicateWellPathFeature.cpp @@ -28,6 +28,7 @@ #include "RimTools.h" #include "RimWellPathCollection.h" #include "RimWellPathGeometryDef.h" +#include "RimWellPathTarget.h" #include "Riu3DMainWindowTools.h" @@ -43,8 +44,7 @@ CAF_CMD_SOURCE_INIT( RicDuplicateWellPathFeature, "RicDuplicateWellPathFeature" //-------------------------------------------------------------------------------------------------- bool RicDuplicateWellPathFeature::isCommandEnabled() const { - auto wellPath = caf::firstAncestorOfTypeFromSelectedObject(); - + auto wellPath = caf::firstAncestorOfTypeFromSelectedObject(); return wellPath != nullptr; } @@ -53,7 +53,7 @@ bool RicDuplicateWellPathFeature::isCommandEnabled() const //-------------------------------------------------------------------------------------------------- void RicDuplicateWellPathFeature::onActionTriggered( bool isChecked ) { - auto sourceWellPath = caf::firstAncestorOfTypeFromSelectedObject(); + auto sourceWellPath = caf::firstAncestorOfTypeFromSelectedObject(); if ( !sourceWellPath ) return; RimProject* project = RimProject::current(); @@ -78,17 +78,11 @@ void RicDuplicateWellPathFeature::onActionTriggered( bool isChecked ) { auto destinationGeometryDef = newModeledWellPath->geometryDefinition(); - const int targetCount = 8; - const auto sourceMDs = sourceWellPath->wellPathGeometry()->measuredDepths(); - const double distanceBetweenTargets = ( sourceMDs.back() - sourceMDs.front() ) / targetCount; - std::vector targetCoordinates; - for ( int targetIdx = 0; targetIdx <= targetCount; targetIdx++ ) + for ( auto target : sourceWellPath->geometryDefinition()->activeWellTargets( false ) ) { - double measuredDepth = sourceMDs.front() + targetIdx * distanceBetweenTargets; - auto sourceCoord = sourceWellPath->wellPathGeometry()->interpolatedPointAlongWellPath( measuredDepth ); - targetCoordinates.push_back( sourceCoord ); + targetCoordinates.push_back( target->targetPointXYZ() ); } destinationGeometryDef->createAndInsertTargets( targetCoordinates ); newModeledWellPath->createWellPathGeometry(); diff --git a/ApplicationLibCode/Commands/WellPathCommands/RicNewEditableWellPathFeature.cpp b/ApplicationLibCode/Commands/WellPathCommands/RicNewEditableWellPathFeature.cpp index d33380e3c4..a497d1c130 100644 --- a/ApplicationLibCode/Commands/WellPathCommands/RicNewEditableWellPathFeature.cpp +++ b/ApplicationLibCode/Commands/WellPathCommands/RicNewEditableWellPathFeature.cpp @@ -19,6 +19,11 @@ #include "RiaColorTables.h" +#include "RigEclipseCaseData.h" +#include "Well/RigWellPath.h" + +#include "RimEclipseCase.h" +#include "RimFileWellPath.h" #include "RimModeledWellPath.h" #include "RimOilField.h" #include "RimProject.h" @@ -26,6 +31,7 @@ #include "RimWellPath.h" #include "RimWellPathCollection.h" #include "RimWellPathGeometryDef.h" + #include "Riu3DMainWindowTools.h" #include "cafSelectionManager.h" @@ -78,6 +84,9 @@ void RicNewEditableWellPathFeature::onActionTriggered( bool isChecked ) newModeledWellPath->setUnitSystem( project->commonUnitSystemForAllCases() ); + RimFileWellPath* sourceWellPath = caf::SelectionManager::instance()->selectedItemOfType(); + bool enableTargetPointPicking = !copyWellPathGeometry( sourceWellPath, newModeledWellPath ); + size_t modelledWellpathCount = wellPathCollection->modelledWellPathCount(); newWellPaths.back()->setName( "Well-" + QString::number( modelledWellpathCount + 1 ) ); @@ -86,7 +95,7 @@ void RicNewEditableWellPathFeature::onActionTriggered( bool isChecked ) wellPathCollection->addWellPaths( newWellPaths ); wellPathCollection->uiCapability()->updateConnectedEditors(); - newModeledWellPath->geometryDefinition()->enableTargetPointPicking( true ); + newModeledWellPath->geometryDefinition()->enableTargetPointPicking( enableTargetPointPicking ); project->scheduleCreateDisplayModelAndRedrawAllViews(); @@ -95,11 +104,90 @@ void RicNewEditableWellPathFeature::onActionTriggered( bool isChecked ) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewEditableWellPathFeature::copyWellPathGeometry( RimFileWellPath* sourceWellPath, RimModeledWellPath* newModeledWellPath ) +{ + if ( sourceWellPath && sourceWellPath->wellPathGeometry() && sourceWellPath->wellPathGeometry()->measuredDepths().size() > 2 ) + { + auto destinationGeometryDef = newModeledWellPath->geometryDefinition(); + + const int targetCount = 8; + + const auto wellPathPoints = sourceWellPath->wellPathGeometry()->wellPathPoints(); + const auto sourceMDs = sourceWellPath->wellPathGeometry()->measuredDepths(); + + auto findCaseContainingAnyPoint = []( const std::vector& points ) -> RimCase* + { + std::vector cases = RimProject::current()->allGridCases(); + for ( RimCase* c : cases ) + { + for ( const cvf::Vec3d& p : points ) + { + if ( c->activeCellsBoundingBox().contains( p ) ) + { + return c; + } + } + } + return nullptr; + }; + + const RimCase* theCase = findCaseContainingAnyPoint( wellPathPoints ); + const double depth = theCase ? theCase->activeCellsBoundingBox().max().z() : 0.0; + + auto filterAwayPointsAboveMinimumDepth = []( const std::vector& wellPathPoints, + const std::vector& md, + double minimumDepth ) -> std::pair, std::vector> + { + // Loop from the top and exclude until the minimum depth has been reached + std::vector filteredPoints; + std::vector filteredMds; + + bool minimumDepthReached = false; + for ( size_t i = 0; i < wellPathPoints.size(); i++ ) + { + if ( wellPathPoints[i].z() < minimumDepth || minimumDepthReached ) + { + filteredPoints.push_back( wellPathPoints[i] ); + filteredMds.push_back( md[i] ); + minimumDepthReached = true; + } + } + + return { filteredPoints, filteredMds }; + }; + + const auto& [filteredWellPathPoints, filteredMDs] = filterAwayPointsAboveMinimumDepth( wellPathPoints, sourceMDs, depth ); + CAF_ASSERT( filteredWellPathPoints.size() == filteredMDs.size() ); + if ( filteredWellPathPoints.size() < 2 ) return false; + + std::vector targetCoordinates; + + const double distanceBetweenTargets = ( filteredMDs.back() - filteredMDs.front() ) / targetCount; + + RigWellPath wellPath( filteredWellPathPoints, filteredMDs ); + + for ( int targetIdx = 0; targetIdx <= targetCount; targetIdx++ ) + { + double measuredDepth = filteredMDs.front() + targetIdx * distanceBetweenTargets; + auto sourceCoord = wellPath.interpolatedPointAlongWellPath( measuredDepth ); + targetCoordinates.push_back( sourceCoord ); + } + destinationGeometryDef->createAndInsertTargets( targetCoordinates ); + newModeledWellPath->createWellPathGeometry(); + return true; + } + + return false; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicNewEditableWellPathFeature::setupActionLook( QAction* actionToSetup ) { - actionToSetup->setText( "Create Well Path" ); - actionToSetup->setIcon( QIcon( ":/Well.svg" ) ); + actionToSetup->setText( "Create Editable Well Path" ); + actionToSetup->setIcon( QIcon( ":/EditableWell.png" ) ); } diff --git a/ApplicationLibCode/Commands/WellPathCommands/RicNewEditableWellPathFeature.h b/ApplicationLibCode/Commands/WellPathCommands/RicNewEditableWellPathFeature.h index 666fb25fc6..7cd1cc514d 100644 --- a/ApplicationLibCode/Commands/WellPathCommands/RicNewEditableWellPathFeature.h +++ b/ApplicationLibCode/Commands/WellPathCommands/RicNewEditableWellPathFeature.h @@ -20,6 +20,9 @@ #include "cafCmdFeature.h" +class RimFileWellPath; +class RimModeledWellPath; + //================================================================================================== /// //================================================================================================== @@ -31,4 +34,6 @@ protected: bool isCommandEnabled() const override; void onActionTriggered( bool isChecked ) override; void setupActionLook( QAction* actionToSetup ) override; + + bool copyWellPathGeometry( RimFileWellPath* sourceWellPath, RimModeledWellPath* newModeledWellPath ); }; diff --git a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp index caa6c1bd7c..b772288505 100644 --- a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -19,6 +19,7 @@ #include "RimContextCommandBuilder.h" +#include "QuickAccess/RimFieldQuickAccess.h" #include "RiaApplication.h" #include "ContourMap/RimEclipseContourMapViewCollection.h" @@ -66,6 +67,7 @@ #include "RimExtrudedCurveIntersection.h" #include "RimFaultInView.h" #include "RimFaultReactivationModel.h" +#include "RimFileWellPath.h" #include "RimFishbones.h" #include "RimFishbonesCollection.h" #include "RimFlowCharacteristicsPlot.h" @@ -363,10 +365,15 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() } else if ( dynamic_cast( firstUiItem ) ) { - menuBuilder << "RicNewEditableWellPathFeature"; + if ( dynamic_cast( firstUiItem ) != nullptr ) + { + menuBuilder << "RicNewEditableWellPathFeature"; + } menuBuilder << "RicNewWellPathLateralFeature"; - menuBuilder << "RicDuplicateWellPathFeature"; - + if ( dynamic_cast( firstUiItem ) != nullptr ) + { + menuBuilder << "RicDuplicateWellPathFeature"; + } menuBuilder.addSeparator(); menuBuilder << "RicSetParentWellPathFeature"; diff --git a/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathGeometryDef.h b/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathGeometryDef.h index f9fa54693b..b89ea59d77 100644 --- a/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathGeometryDef.h +++ b/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathGeometryDef.h @@ -77,6 +77,7 @@ public: const RimWellPathTarget* firstActiveTarget() const; const RimWellPathTarget* lastActiveTarget() const; std::vector activeWellTargets() const; + std::vector activeWellTargets( bool useAutoGeneratedTargetAtSeaLevel ) const; void enableTargetPointPicking( bool isEnabling ); void updateWellPathVisualization( bool fullUpdate ); @@ -93,7 +94,6 @@ public: double wellTargetScalingFactor() const; protected: - std::vector activeWellTargets( bool useAutoGeneratedTargetAtSeaLevel ) const; cvf::ref createWellPathGeometry( bool useAutoGeneratedTargetAtSeaLevel, double offsetMd, bool updateTargets ) const; void defineCustomContextMenu( const caf::PdmFieldHandle* fieldNeedingMenu, QMenu* menu, QWidget* fieldEditorWidget ) override;