2018-07-03 08:42:31 +02:00
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018 - equinor 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 "RimWellPathGeometryDef.h"
#include "cafCmdFeatureMenuBuilder.h"
#include "cafPdmUiTableViewEditor.h"
#include "cafPdmUiTreeOrdering.h"
#include "RigWellPath.h"
#include "RiaPolyArcLineSampler.h"
#include "RimWellPathTarget.h"
#include "RimModeledWellPath.h"
2018-07-04 16:49:04 +02:00
#include "RiaSCurveCalculator.h"
2018-08-07 13:15:41 +02:00
#include "RiaLogging.h"
2018-08-14 11:25:08 +02:00
#include "RiaJCurveCalculator.h"
2018-08-29 16:03:31 +02:00
#include "cafPdmUiPushButtonEditor.h"
#include "WellPathCommands/RicCreateWellTargetsPickEventHandler.h"
#include "RiuViewerCommands.h"
2018-07-03 08:42:31 +02:00
namespace caf
{
template <>
void caf :: AppEnum < RimWellPathGeometryDef :: WellStartType >:: setUp ()
{
addItem ( RimWellPathGeometryDef :: START_AT_FIRST_TARGET , "START_AT_FIRST_TARGET" , "Start at First Target" );
addItem ( RimWellPathGeometryDef :: START_AT_SURFACE , "START_AT_SURFACE" , "Start at Surface" );
addItem ( RimWellPathGeometryDef :: START_FROM_OTHER_WELL , "START_FROM_OTHER_WELL" , "Branch" );
addItem ( RimWellPathGeometryDef :: START_AT_AUTO_SURFACE , "START_AT_AUTO_SURFACE" , "Auto Surface" );
setDefault ( RimWellPathGeometryDef :: START_AT_FIRST_TARGET );
}
}
CAF_PDM_SOURCE_INIT ( RimWellPathGeometryDef , "WellPathGeometryDef" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimWellPathGeometryDef :: RimWellPathGeometryDef ()
2018-08-29 16:03:31 +02:00
: m_pickTargetsEventHandler ( new RicCreateWellTargetsPickEventHandler ( this ))
2018-07-03 08:42:31 +02:00
{
CAF_PDM_InitObject ( "Trajectory" , ":/Well.png" , "" , "" );
CAF_PDM_InitFieldNoDefault ( & m_wellStartType , "WellStartType" , "Start Type" , "" , "" , "" );
2018-08-29 16:03:31 +02:00
CAF_PDM_InitField ( & m_referencePointXyz , "ReferencePos" , cvf :: Vec3d ( 0 , 0 , 0 ), "UTM Reference Point" , "" , "" , "" );
2018-07-03 08:42:31 +02:00
CAF_PDM_InitFieldNoDefault ( & m_parentWell , "ParentWell" , "Parent Well" , "" , "" , "" );
CAF_PDM_InitField ( & m_kickoffDepthOrMD , "KickoffDepthOrMD" , 100.0 , "Kickoff Depth" , "" , "" , "" );
CAF_PDM_InitFieldNoDefault ( & m_wellTargets , "WellPathTargets" , "Well Targets" , "" , "" , "" );
m_wellTargets . uiCapability () -> setUiEditorTypeName ( caf :: PdmUiTableViewEditor :: uiEditorTypeName ());
//m_wellTargets.uiCapability()->setUiTreeHidden(true);
m_wellTargets . uiCapability () -> setUiTreeChildrenHidden ( true );
m_wellTargets . uiCapability () -> setUiLabelPosition ( caf :: PdmUiItemInfo :: TOP );
m_wellTargets . uiCapability () -> setCustomContextMenuEnabled ( true );
2018-08-29 16:03:31 +02:00
CAF_PDM_InitField ( & m_pickPointsEnabled , "m_pickPointsEnabled" , false , "" , "" , "" , "" );
caf :: PdmUiPushButtonEditor :: configureEditorForField ( & m_pickPointsEnabled );
2018-07-03 08:42:31 +02:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimWellPathGeometryDef ::~ RimWellPathGeometryDef ()
{
2018-08-30 13:22:28 +02:00
RiuViewerCommands :: removePickEventHandlerIfActive ( m_pickTargetsEventHandler );
2018-08-29 16:03:31 +02:00
delete m_pickTargetsEventHandler ;
2018-07-03 08:42:31 +02:00
2018-08-29 16:03:31 +02:00
m_pickTargetsEventHandler = nullptr ;
2018-07-03 08:42:31 +02:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf :: ref < RigWellPath > RimWellPathGeometryDef :: createWellPathGeometry ()
{
cvf :: ref < RigWellPath > wellPathGeometry = new RigWellPath ;
2018-07-31 08:44:37 +02:00
if ( activeWellTargets (). size () < 2 ) return wellPathGeometry ;
2018-07-03 08:42:31 +02:00
2018-07-04 16:49:04 +02:00
RiaPolyArcLineSampler arcLineSampler ( startTangent (), lineArcEndpoints ());
2018-07-03 08:42:31 +02:00
arcLineSampler . sampledPointsAndMDs ( 30 ,
false ,
& ( wellPathGeometry -> m_wellPathPoints ),
& ( wellPathGeometry -> m_measuredDepths ));
return wellPathGeometry ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellPathGeometryDef :: updateWellPathVisualization ()
{
RimModeledWellPath * modWellPath ;
this -> firstAncestorOrThisOfTypeAsserted ( modWellPath );
modWellPath -> updateWellPathVisualization ();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2018-08-29 16:03:31 +02:00
void RimWellPathGeometryDef :: insertTarget ( const RimWellPathTarget * targetToInsertBefore , RimWellPathTarget * targetToInsert )
2018-07-03 08:42:31 +02:00
{
size_t index = m_wellTargets . index ( targetToInsertBefore );
if ( index < m_wellTargets . size ()) m_wellTargets . insert ( index , targetToInsert );
else m_wellTargets . push_back ( targetToInsert );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellPathGeometryDef :: deleteTarget ( RimWellPathTarget * targetTodelete )
{
m_wellTargets . removeChildObject ( targetTodelete );
delete targetTodelete ;
}
2018-07-31 11:44:15 +02:00
//--------------------------------------------------------------------------------------------------
2018-08-06 07:52:02 +02:00
///
2018-07-31 11:44:15 +02:00
//--------------------------------------------------------------------------------------------------
void RimWellPathGeometryDef :: appendTarget ()
{
RimWellPathTarget * wellPathTarget = nullptr ;
auto targets = m_wellTargets . childObjects ();
if ( targets . empty ())
{
wellPathTarget = new RimWellPathTarget ;
}
else
{
wellPathTarget = dynamic_cast < RimWellPathTarget *> ( targets . back () -> xmlCapability () -> copyByXmlSerialization ( caf :: PdmDefaultObjectFactory :: instance ()));
}
if ( wellPathTarget )
{
m_wellTargets . push_back ( wellPathTarget );
}
}
2018-08-14 14:23:55 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RimWellPathTarget * RimWellPathGeometryDef :: firstActiveTarget () const
{
for ( const RimWellPathTarget * target : m_wellTargets )
{
if ( target -> isEnabled ())
{
return target ;
}
}
return nullptr ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RimWellPathTarget * RimWellPathGeometryDef :: lastActiveTarget () const
{
if ( ! m_wellTargets . size ()) return nullptr ;
for ( int tIdx = static_cast < int > ( m_wellTargets . size () - 1 ); tIdx >= 0 ; -- tIdx )
{
if ( m_wellTargets [ tIdx ] -> isEnabled ())
{
return m_wellTargets [ tIdx ];
}
}
return nullptr ;
}
2018-08-29 16:03:31 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellPathGeometryDef :: enableTargetPointPicking ( bool isEnabling )
{
if ( isEnabling )
{
m_pickPointsEnabled = true ;
2018-08-30 13:22:28 +02:00
RiuViewerCommands :: setPickEventHandler ( m_pickTargetsEventHandler );
2018-08-29 16:03:31 +02:00
updateConnectedEditors ();
}
else
{
2018-08-30 13:22:28 +02:00
RiuViewerCommands :: removePickEventHandlerIfActive ( m_pickTargetsEventHandler );
2018-08-29 16:03:31 +02:00
m_pickPointsEnabled = false ;
updateConnectedEditors ();
}
}
2018-07-04 16:49:04 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList < caf :: PdmOptionItemInfo > RimWellPathGeometryDef :: calculateValueOptions ( const caf :: PdmFieldHandle * fieldNeedingOptions ,
bool * useOptionsOnly )
{
QList < caf :: PdmOptionItemInfo > options ;
if ( fieldNeedingOptions == & m_wellStartType )
{
options . push_back ( caf :: PdmOptionItemInfo ( "Start at First Target" , RimWellPathGeometryDef :: START_AT_FIRST_TARGET ));
}
return options ;
}
2018-07-03 08:42:31 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellPathGeometryDef :: fieldChangedByUi ( const caf :: PdmFieldHandle * changedField ,
const QVariant & oldValue ,
const QVariant & newValue )
{
2018-08-29 16:03:31 +02:00
if ( & m_referencePointXyz == changedField )
2018-07-03 08:42:31 +02:00
{
std :: cout << "fieldChanged" << std :: endl ;
}
2018-08-29 16:03:31 +02:00
else if ( changedField == & m_pickPointsEnabled )
{
enableTargetPointPicking ( m_pickPointsEnabled );
}
2018-07-03 08:42:31 +02:00
updateWellPathVisualization ();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellPathGeometryDef :: defineUiOrdering ( QString uiConfigName , caf :: PdmUiOrdering & uiOrdering )
{
uiOrdering . add ( & m_wellStartType );
if ( m_wellStartType == START_FROM_OTHER_WELL )
{
uiOrdering . add ( & m_parentWell );
m_kickoffDepthOrMD . uiCapability () -> setUiName ( "Measured Depth" );
uiOrdering . add ( & m_kickoffDepthOrMD );
}
if ( m_wellStartType == START_AT_SURFACE )
{
m_kickoffDepthOrMD . uiCapability () -> setUiName ( "Kick-Off Depth" );
uiOrdering . add ( & m_kickoffDepthOrMD );
}
2018-08-29 16:03:31 +02:00
uiOrdering . add ( & m_referencePointXyz );
2018-07-03 08:42:31 +02:00
uiOrdering . add ( & m_wellTargets );
2018-08-29 16:03:31 +02:00
uiOrdering . add ( & m_pickPointsEnabled );
2018-07-03 08:42:31 +02:00
uiOrdering . skipRemainingFields ( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellPathGeometryDef :: defineUiTreeOrdering ( caf :: PdmUiTreeOrdering & uiTreeOrdering , QString uiConfigName )
{
uiTreeOrdering . skipRemainingChildren ( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2018-07-31 08:44:37 +02:00
std :: vector < RimWellPathTarget *> RimWellPathGeometryDef :: activeWellTargets () const
2018-07-03 08:42:31 +02:00
{
2018-07-31 08:44:37 +02:00
std :: vector < RimWellPathTarget *> active ;
for ( const auto & wt : m_wellTargets )
{
if ( wt -> isEnabled ())
{
active . push_back ( wt );
}
}
2018-07-04 16:49:04 +02:00
2018-07-31 08:44:37 +02:00
return active ;
}
2018-07-04 16:49:04 +02:00
2018-07-31 08:44:37 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std :: vector < cvf :: Vec3d > RimWellPathGeometryDef :: lineArcEndpoints () const
{
2018-08-14 11:25:08 +02:00
double prevSegmentEndAzi = 0 ;
double prevSegmentEndInc = 0 ;
2018-07-31 08:44:37 +02:00
std :: vector < RimWellPathTarget *> activeWellPathTargets = activeWellTargets ();
CVF_ASSERT ( activeWellPathTargets . size () > 1 );
2018-07-04 16:49:04 +02:00
2018-07-31 08:44:37 +02:00
std :: vector < cvf :: Vec3d > endPoints ;
2018-08-29 16:03:31 +02:00
endPoints . push_back ( activeWellPathTargets [ 0 ] -> targetPointXYZ () + m_referencePointXyz () );
2018-07-04 16:49:04 +02:00
2018-07-31 08:44:37 +02:00
for ( size_t tIdx = 0 ; tIdx < activeWellPathTargets . size () - 1 ; ++ tIdx )
{
RimWellPathTarget * target1 = activeWellPathTargets [ tIdx ];
RimWellPathTarget * target2 = activeWellPathTargets [ tIdx + 1 ];
2018-07-04 16:49:04 +02:00
2018-08-14 11:25:08 +02:00
if ( target1 -> targetType () == RimWellPathTarget :: POINT_AND_TANGENT
2018-07-04 16:49:04 +02:00
&& target2 -> targetType () == RimWellPathTarget :: POINT_AND_TANGENT )
{
RiaSCurveCalculator sCurveCalc ( target1 -> targetPointXYZ (),
target1 -> azimuth (),
target1 -> inclination (),
2018-08-14 11:25:08 +02:00
target1 -> radius2 (),
2018-07-04 16:49:04 +02:00
target2 -> targetPointXYZ (),
target2 -> azimuth (),
target2 -> inclination (),
2018-08-14 11:25:08 +02:00
target2 -> radius1 ());
2018-07-04 16:49:04 +02:00
2018-08-07 13:15:41 +02:00
if ( ! sCurveCalc . isOk ())
{
2018-08-10 12:10:39 +02:00
double p1p2Length = ( target2 -> targetPointXYZ () - target1 -> targetPointXYZ ()). length ();
2018-08-07 13:15:41 +02:00
sCurveCalc = RiaSCurveCalculator :: fromTangentsAndLength ( target1 -> targetPointXYZ (),
target1 -> azimuth (),
target1 -> inclination (),
2018-08-10 12:10:39 +02:00
0.2 * p1p2Length ,
2018-08-07 13:15:41 +02:00
target2 -> targetPointXYZ (),
target2 -> azimuth (),
target2 -> inclination (),
2018-08-10 12:10:39 +02:00
0.2 * p1p2Length );
2018-08-10 15:22:43 +02:00
RiaLogging :: warning ( "Using fall-back calculation of well path geometry between active target number: " + QString :: number ( tIdx + 1 ) + " and " + QString :: number ( tIdx + 2 ));
2018-08-07 13:15:41 +02:00
}
2018-08-14 11:25:08 +02:00
2018-08-29 16:03:31 +02:00
endPoints . push_back ( sCurveCalc . firstArcEndpoint () + m_referencePointXyz () );
endPoints . push_back ( sCurveCalc . secondArcStartpoint () + m_referencePointXyz () );
endPoints . push_back ( target2 -> targetPointXYZ () + m_referencePointXyz () );
2018-08-14 11:25:08 +02:00
}
else if ( target1 -> targetType () == RimWellPathTarget :: POINT
&& target2 -> targetType () == RimWellPathTarget :: POINT_AND_TANGENT )
{
RiaSCurveCalculator sCurveCalc ( target1 -> targetPointXYZ (),
prevSegmentEndAzi ,
prevSegmentEndInc ,
target1 -> radius2 (),
target2 -> targetPointXYZ (),
target2 -> azimuth (),
target2 -> inclination (),
target2 -> radius1 ());
if ( ! sCurveCalc . isOk ())
{
double p1p2Length = ( target2 -> targetPointXYZ () - target1 -> targetPointXYZ ()). length ();
sCurveCalc = RiaSCurveCalculator :: fromTangentsAndLength ( target1 -> targetPointXYZ (),
prevSegmentEndAzi ,
prevSegmentEndInc ,
0.2 * p1p2Length ,
target2 -> targetPointXYZ (),
target2 -> azimuth (),
target2 -> inclination (),
0.2 * p1p2Length );
RiaLogging :: warning ( "Using fall-back calculation of well path geometry between active target number: " + QString :: number ( tIdx + 1 ) + " and " + QString :: number ( tIdx + 2 ));
}
2018-08-29 16:03:31 +02:00
endPoints . push_back ( sCurveCalc . firstArcEndpoint () + m_referencePointXyz () );
endPoints . push_back ( sCurveCalc . secondArcStartpoint () + m_referencePointXyz () );
endPoints . push_back ( target2 -> targetPointXYZ () + m_referencePointXyz () );
2018-08-14 11:25:08 +02:00
}
else if ( target1 -> targetType () == RimWellPathTarget :: POINT_AND_TANGENT
&& target2 -> targetType () == RimWellPathTarget :: POINT )
{
RiaJCurveCalculator jCurve ( target1 -> targetPointXYZ (),
target1 -> azimuth (),
target1 -> inclination (),
target1 -> radius2 (),
target2 -> targetPointXYZ ());
if ( jCurve . isOk () )
{
2018-08-29 16:03:31 +02:00
endPoints . push_back ( jCurve . firstArcEndpoint () + m_referencePointXyz ());
2018-08-14 11:25:08 +02:00
}
2018-08-29 16:03:31 +02:00
endPoints . push_back ( target2 -> targetPointXYZ () + m_referencePointXyz () );
2018-08-14 11:25:08 +02:00
prevSegmentEndAzi = jCurve . endAzimuth ();
prevSegmentEndInc = jCurve . endInclination ();
2018-07-04 16:49:04 +02:00
}
2018-08-14 11:25:08 +02:00
else if ( target1 -> targetType () == RimWellPathTarget :: POINT
&& target2 -> targetType () == RimWellPathTarget :: POINT )
{
RiaJCurveCalculator jCurve ( target1 -> targetPointXYZ (),
prevSegmentEndAzi ,
prevSegmentEndInc ,
target1 -> radius2 (),
target2 -> targetPointXYZ ());
if ( jCurve . isOk () )
{
2018-08-29 16:03:31 +02:00
endPoints . push_back ( jCurve . firstArcEndpoint () + m_referencePointXyz ());
2018-08-14 11:25:08 +02:00
}
2018-08-29 16:03:31 +02:00
endPoints . push_back ( target2 -> targetPointXYZ () + m_referencePointXyz () );
2018-08-14 11:25:08 +02:00
prevSegmentEndAzi = jCurve . endAzimuth ();
prevSegmentEndInc = jCurve . endInclination ();
}
else
{
CVF_ASSERT ( false );
}
2018-07-03 08:42:31 +02:00
}
return endPoints ;
}
2018-07-04 16:49:04 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2018-07-31 08:44:37 +02:00
cvf :: Vec3d RimWellPathGeometryDef :: startTangent () const
2018-07-04 16:49:04 +02:00
{
2018-07-31 08:44:37 +02:00
std :: vector < RimWellPathTarget *> wellTargets = activeWellTargets ();
if ( ! wellTargets . empty () && wellTargets [ 0 ] -> targetType () == RimWellPathTarget :: POINT_AND_TANGENT )
2018-07-04 16:49:04 +02:00
{
2018-07-31 08:44:37 +02:00
return wellTargets [ 0 ] -> tangent ();
2018-07-04 16:49:04 +02:00
}
else
{
2018-07-31 08:44:37 +02:00
return { 0 , 0 , - 1 };
2018-07-04 16:49:04 +02:00
}
}
2018-07-03 08:42:31 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellPathGeometryDef :: defineCustomContextMenu ( const caf :: PdmFieldHandle * fieldNeedingMenu ,
QMenu * menu ,
QWidget * fieldEditorWidget )
{
caf :: CmdFeatureMenuBuilder menuBuilder ;
menuBuilder << "RicNewWellPathListTargetFeature" ;
menuBuilder << "Separator" ;
menuBuilder << "RicDeleteWellPathTargetFeature" ;
menuBuilder . appendToMenu ( menu );
}
2018-08-29 16:03:31 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellPathGeometryDef :: defineEditorAttribute ( const caf :: PdmFieldHandle * field , QString uiConfigName , caf :: PdmUiEditorAttribute * attribute )
{
if ( field == & m_pickPointsEnabled )
{
caf :: PdmUiPushButtonEditorAttribute * pbAttribute = dynamic_cast < caf :: PdmUiPushButtonEditorAttribute *> ( attribute );
if ( pbAttribute )
{
if ( ! m_pickPointsEnabled )
{
pbAttribute -> m_buttonText = "Start Picking Targets" ;
}
else
{
pbAttribute -> m_buttonText = "Stop Picking Targets" ;
}
}
}
if ( field == & m_wellTargets )
{
auto tvAttribute = dynamic_cast < caf :: PdmUiTableViewEditorAttribute *> ( attribute );
if ( tvAttribute && m_pickPointsEnabled )
{
tvAttribute -> baseColor . setRgb ( 255 , 220 , 255 );
2018-08-29 17:08:03 +02:00
tvAttribute -> forceColumnWidthResize = true ;
2018-08-29 16:03:31 +02:00
}
}
}