From 5329000cef6285d57edc215edf771ce682ae9c6d Mon Sep 17 00:00:00 2001 From: mzn Date: Fri, 27 Mar 2015 17:48:59 +0300 Subject: [PATCH] refs #492: Implement bottom of the river creation in the data model --- src/HYDROData/HYDROData_Profile.cxx | 54 ++++++++++ src/HYDROData/HYDROData_Profile.h | 7 ++ src/HYDROData/HYDROData_Stream.cxx | 126 +++++++++++++++++++++++- src/HYDROData/HYDROData_Stream.h | 15 ++- src/HYDROGUI/HYDROGUI_DataModel.cxx | 5 + src/HYDROGUI/HYDROGUI_RiverBottomOp.cxx | 8 +- src/HYDROGUI/HYDROGUI_RiverBottomOp.h | 4 +- src/HYDROPy/HYDROData_Stream.sip | 21 ++++ 8 files changed, 233 insertions(+), 7 deletions(-) diff --git a/src/HYDROData/HYDROData_Profile.cxx b/src/HYDROData/HYDROData_Profile.cxx index b970af45..3a628a74 100755 --- a/src/HYDROData/HYDROData_Profile.cxx +++ b/src/HYDROData/HYDROData_Profile.cxx @@ -663,4 +663,58 @@ void HYDROData_Profile::UpdateLocalCS( double theDx, double theDy ) SetRightPoint( aPnt, false ); } +HYDROData_Profile::ProfilePoint HYDROData_Profile::GetBottomPoint() const +{ + ProfilePoint aBottom; + + // Get parametric points + HYDROData_ProfileUZ::PointsList aParametricPoints = GetParametricPoints(); + if ( aParametricPoints.Length() < 1 ) { + return aBottom; + } + + // Calculate midvalue for U parameter + Standard_Real anUMidValue = aParametricPoints.First().X(); + Standard_Real anUMinValue = anUMidValue; + Standard_Real anUMaxValue = anUMidValue; + + for ( int i = 2, aNbPoints = aParametricPoints.Size(); i <= aNbPoints; i++ ) { + const HYDROData_IPolyline::Point& aParPoint = aParametricPoints.Value( i ); + Standard_Real anU = aParPoint.X(); + + if ( anU < anUMinValue ) { + anUMinValue = anU; + } else if ( anU > anUMaxValue ) { + anUMaxValue = anU; + } + } + + anUMidValue = ( anUMinValue + anUMaxValue ) / 2; + + // Find index of the parametric point with minimal Z value + int aBottomIndex = 1; + HYDROData_IPolyline::Point aParBottom = aParametricPoints.First(); + + for ( int i = 2, aNbPoints = aParametricPoints.Size(); i <= aNbPoints; i++ ) { + const HYDROData_IPolyline::Point& aParPoint = aParametricPoints.Value( i ); + if ( aParPoint.Y() < aParBottom.Y() ) { + aBottomIndex = i; + aParBottom = aParPoint; + } else if ( aParPoint.Y() == aParBottom.Y() ) { + // Check which point is neares to the U = 0.5 + if ( fabs( aParPoint.X() - anUMidValue ) < fabs( aParBottom.X() - anUMidValue ) ) { + aBottomIndex = i; + aParBottom = aParPoint; + } + } + } + + // Find the corresponding profile point + ProfilePoints aProfilePoints = GetProfilePoints( false ); + if ( aBottomIndex >= 1 && aBottomIndex <= aProfilePoints.Length() ) { + aBottom = aProfilePoints.Value( aBottomIndex ); + } + + return aBottom; +} diff --git a/src/HYDROData/HYDROData_Profile.h b/src/HYDROData/HYDROData_Profile.h index 14701053..03339e1f 100644 --- a/src/HYDROData/HYDROData_Profile.h +++ b/src/HYDROData/HYDROData_Profile.h @@ -191,6 +191,13 @@ public: */ HYDRODATA_EXPORT ProfilePoints GetProfilePoints( bool IsConvertToGlobal = false ) const; + + /** + * Return profile point with minimal Z value. + * \return non-parametric profile point + */ + HYDRODATA_EXPORT ProfilePoint GetBottomPoint() const; + public: // Public methods to work with files. diff --git a/src/HYDROData/HYDROData_Stream.cxx b/src/HYDROData/HYDROData_Stream.cxx index 9573c8bd..656e1b02 100644 --- a/src/HYDROData/HYDROData_Stream.cxx +++ b/src/HYDROData/HYDROData_Stream.cxx @@ -24,10 +24,12 @@ #include "HYDROData_Document.h" #include "HYDROData_PolylineXY.h" +#include "HYDROData_Polyline3D.h" #include "HYDROData_Profile.h" #include "HYDROData_ShapesGroup.h" #include "HYDROData_ShapesTool.h" #include "HYDROData_IAltitudeObject.h" +#include "HYDROData_Tool.h" #include @@ -119,6 +121,12 @@ QStringList HYDROData_Stream::DumpToPython( MapOfTreatedObjects& theTreatedObjec setPythonReferenceObject( theTreatedObjects, aResList, aProfile, "AddProfile" ); } + // Create bottom polyline if exists + const Handle(HYDROData_Polyline3D) aBottomPolyline = GetBottomPolyline(); + if ( !aBottomPolyline.IsNull() ) { + aResList << QString( "%1.GenerateBottomPolyline();" ).arg( aName ); + } + aResList << QString( "" ); aResList << QString( "%1.Update();" ).arg( aName ); aResList << QString( "" ); @@ -164,6 +172,19 @@ Handle(Geom_BSplineCurve) HYDROData_Stream::buildInterpolationCurve( void HYDROData_Stream::Update() { updateProfilesOrder(); + + // Update bottom polyline if exists + const Handle(HYDROData_Polyline3D) aBottomPolyline = GetBottomPolyline(); + if ( !aBottomPolyline.IsNull() ) { + if ( GenerateBottomPolyline() ) { + Handle(HYDROData_PolylineXY) aPolylineXY = aBottomPolyline->GetPolylineXY(); + if ( !aPolylineXY.IsNull() ) { + aPolylineXY->Update(); + } + aBottomPolyline->Update(); + } + } + UpdatePrs(); } @@ -382,7 +403,7 @@ void HYDROData_Stream::UpdatePrs() anInGroup->AddShape( aResultPrs.myInlet ); QString anOutGroupName = GetName() + "_Outlet"; - + Handle(HYDROData_ShapesGroup) anOutGroup = createGroupObject(); anOutGroup->SetName( anOutGroupName ); anOutGroup->AddShape( aResultPrs.myOutlet ); @@ -997,3 +1018,106 @@ void HYDROData_Stream::removeParameter( const int& theIndex ) setParametersArray( aNewArr ); } + +bool HYDROData_Stream::GenerateBottomPolyline() +{ + // Get the document + Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab ); + if ( aDocument.IsNull() ) { + return false; + } + + // Collect bottom points ( one bottom point from each profile of the stream ) + HYDROData_Profile::ProfilePoints aBottomPoints; + + HYDROData_SequenceOfObjects aSeqOfProfiles = GetProfiles(); + for ( int i = 1, aNb = aSeqOfProfiles.Size(); i <= aNb; i++ ) { + const Handle(HYDROData_Profile) aProfile = + Handle(HYDROData_Profile)::DownCast( aSeqOfProfiles.Value( i ) ); + if ( aProfile.IsNull() ) { + continue; + } + + aBottomPoints.Append( aProfile->GetBottomPoint() ); + } + + int aNbBottomPoints = aBottomPoints.Size(); + + if ( aNbBottomPoints < 2 ) { + return false; + } + + // Create bottom polyline object if the stream doesn't contain it yet + Handle(HYDROData_Polyline3D) aBottom = GetBottomPolyline(); + if ( aBottom.IsNull() ) { + aBottom = Handle(HYDROData_Polyline3D)::DownCast( aDocument->CreateObject( KIND_POLYLINE ) ); + QString aBaseName = GetName() + "_bottom"; + QString aName = HYDROData_Tool::GenerateObjectName( aDocument, aBaseName, QStringList(), true ); + aBottom->SetName( aName ); + + SetReferenceObject( aBottom, DataTag_BottomPolyline ); + } + + // Create 2D polyline if the bottom polyline doesn't contain it yet + Handle(HYDROData_PolylineXY) aPolylineXY = aBottom->GetPolylineXY(); + if ( aPolylineXY.IsNull() ) { + aPolylineXY = Handle(HYDROData_PolylineXY)::DownCast( aDocument->CreateObject( KIND_POLYLINEXY ) ); + QString aBaseName = GetName() + "_bottom_2d"; + QString aName = HYDROData_Tool::GenerateObjectName( aDocument, aBaseName, QStringList(), true ); + aPolylineXY->SetName( aName ); + aBottom->SetPolylineXY( aPolylineXY, false ); + } + + aPolylineXY->RemoveSections(); + aPolylineXY->AddSection( "", HYDROData_PolylineXY::SECTION_SPLINE, false ); + + // Create profile if the bottom polyline doesn't contain it yet + Handle(HYDROData_ProfileUZ) aProfileUZ = aBottom->GetProfileUZ(); + if ( aProfileUZ.IsNull() ) { + Handle(HYDROData_Profile) aProfile = + Handle(HYDROData_Profile)::DownCast( aDocument->CreateObject( KIND_PROFILE ) ); + QString aBaseName = GetName() + "_bottom_profile"; + QString aName = HYDROData_Tool::GenerateObjectName( aDocument, aBaseName, QStringList(), true ); + aProfile->SetName( aName ); + aProfileUZ = aProfile->GetProfileUZ( true ); + aBottom->SetProfileUZ( aProfileUZ ); + } + + aProfileUZ->RemoveSection( 0 ); + + // Fill 2D polyline + for ( int i = 1; i <= aNbBottomPoints; i++ ) { + const HYDROData_Profile::ProfilePoint& aBottomPoint = aBottomPoints.Value( i ); + aPolylineXY->AddPoint( 0, HYDROData_PolylineXY::Point( aBottomPoint.X(), aBottomPoint.Y() ) ); + } + + // Calculate profile UZ points + + // First point + const HYDROData_Profile::ProfilePoint& aFirstBottomPoint = aBottomPoints.First(); + aProfileUZ->AddPoint( 0, HYDROData_ProfileUZ::Point( 0, aFirstBottomPoint.Z() ) ); + + // Intermediate points + double aPolylineCommonDist = aPolylineXY->GetDistance( 0, aPolylineXY->NbPoints( 0 ) - 1 ); + + for ( int i = 2, aNbPoints = aBottomPoints.Size(); i < aNbPoints; i++ ) { + const HYDROData_Profile::ProfilePoint& aBottomPoint = aBottomPoints.Value( i ); + + double aDistance = aPolylineXY->GetDistance( 0, i - 1 ); + + Standard_Real anU = aDistance; // = ( aDistance / aPolylineCommonDist ) * aPolylineCommonDist; + aProfileUZ->AddPoint( 0, HYDROData_ProfileUZ::Point( anU, aBottomPoint.Z() ) ); + } + + // Last point + const HYDROData_Profile::ProfilePoint& aLastBottomPoint = aBottomPoints.Last(); + aProfileUZ->AddPoint( 0, HYDROData_ProfileUZ::Point( aPolylineCommonDist, aLastBottomPoint.Z() ) ); + + return true; +} + +Handle(HYDROData_Polyline3D) HYDROData_Stream::GetBottomPolyline() const +{ + return Handle(HYDROData_Polyline3D)::DownCast( + GetReferenceObject( DataTag_BottomPolyline ) ); +} diff --git a/src/HYDROData/HYDROData_Stream.h b/src/HYDROData/HYDROData_Stream.h index 45a81943..4af7d1c6 100644 --- a/src/HYDROData/HYDROData_Stream.h +++ b/src/HYDROData/HYDROData_Stream.h @@ -33,6 +33,7 @@ DEFINE_STANDARD_HANDLE(HYDROData_Stream, HYDROData_NaturalObject) class Handle(HYDROData_PolylineXY); +class Handle(HYDROData_Polyline3D); class Handle(HYDROData_Profile); class TColStd_Array1OfReal; @@ -63,7 +64,8 @@ protected: DataTag_First = HYDROData_NaturalObject::DataTag_First + 100, ///< first tag, to reserve DataTag_HydraulicAxis, ///< reference hydraulic axis DataTag_Profile, ///< reference profiles - DataTag_ParamsArray ///< parameters array + DataTag_ParamsArray, ///< parameters array + DataTag_BottomPolyline ///< reference bottom polyline }; public: @@ -229,6 +231,17 @@ public: * Removes all reference profile objects from stream. */ HYDRODATA_EXPORT virtual void RemoveProfiles(); + + /** + * Generates bottom polyline for stream or update the existing bottom polyline. + * \return true in case of success + */ + HYDRODATA_EXPORT virtual bool GenerateBottomPolyline(); + + /** + * Returns reference bottom polyline object of stream. + */ + HYDRODATA_EXPORT virtual Handle(HYDROData_Polyline3D) GetBottomPolyline() const; protected: diff --git a/src/HYDROGUI/HYDROGUI_DataModel.cxx b/src/HYDROGUI/HYDROGUI_DataModel.cxx index d061b7de..37e4ec0b 100644 --- a/src/HYDROGUI/HYDROGUI_DataModel.cxx +++ b/src/HYDROGUI/HYDROGUI_DataModel.cxx @@ -982,6 +982,11 @@ void HYDROGUI_DataModel::buildObjectTree( SUIT_DataObject* theParent, HYDROData_SequenceOfObjects aProfiles = aStreamObj->GetProfiles(); buildObjectPartition( aGuiObj, aProfiles, tr( "STREAM_PROFILES" ), true ); + + Handle(HYDROData_Polyline3D) aBottomPolyline = aStreamObj->GetBottomPolyline(); + if ( !aBottomPolyline.IsNull() && !aBottomPolyline->IsRemoved() ) { + createObject( aGuiObj, aBottomPolyline, aGuiObj->entry(), false ); + } } } diff --git a/src/HYDROGUI/HYDROGUI_RiverBottomOp.cxx b/src/HYDROGUI/HYDROGUI_RiverBottomOp.cxx index f0312216..3bd6c64f 100644 --- a/src/HYDROGUI/HYDROGUI_RiverBottomOp.cxx +++ b/src/HYDROGUI/HYDROGUI_RiverBottomOp.cxx @@ -98,7 +98,7 @@ bool HYDROGUI_RiverBottomOp::processApply( int& theUpdateFlags, QString& theErro if ( !aPanel ) return false; - Handle(HYDROData_River) aRiver = riverObject( aPanel->getRiverName() ); + Handle(HYDROData_Stream) aRiver = riverObject( aPanel->getRiverName() ); if ( aRiver.IsNull() ) { theErrorMsg = tr( "INCORRECT_RIVER_OBJECT" ); @@ -107,6 +107,8 @@ bool HYDROGUI_RiverBottomOp::processApply( int& theUpdateFlags, QString& theErro startDocOperation(); + aRiver->GenerateBottomPolyline(); + aRiver->Update(); // Handle(HYDRO_RiverBottom) aBottom = createNewObject(); // aBottom->SetName( QString( "%1_Bottom" ).arg( aRiver->GetName() ) ); @@ -130,9 +132,9 @@ Handle(HYDROData_RiverBottom) HYDROGUI_RiverBottomOp::createNewObject() } */ -Handle(HYDROData_River) HYDROGUI_RiverBottomOp::riverObject( const QString& theName ) const +Handle(HYDROData_Stream) HYDROGUI_RiverBottomOp::riverObject( const QString& theName ) const { - return Handle(HYDROData_River)::DownCast( HYDROGUI_Tool::FindObjectByName( module(), theName ) ); + return Handle(HYDROData_Stream)::DownCast( HYDROGUI_Tool::FindObjectByName( module(), theName ) ); } QStringList HYDROGUI_RiverBottomOp::riverNames( bool all ) const { diff --git a/src/HYDROGUI/HYDROGUI_RiverBottomOp.h b/src/HYDROGUI/HYDROGUI_RiverBottomOp.h index b99b666f..525df1f7 100644 --- a/src/HYDROGUI/HYDROGUI_RiverBottomOp.h +++ b/src/HYDROGUI/HYDROGUI_RiverBottomOp.h @@ -25,7 +25,7 @@ #include "HYDROGUI_Operation.h" -#include +#include class HYDROGUI_RiverBottomOp : public HYDROGUI_Operation { @@ -46,7 +46,7 @@ protected: QStringList& theBrowseObjectsEntries ); private: - Handle(HYDROData_River) riverObject( const QString& ) const; + Handle(HYDROData_Stream) riverObject( const QString& ) const; QStringList riverNames( bool all = false ) const; protected: diff --git a/src/HYDROPy/HYDROData_Stream.sip b/src/HYDROPy/HYDROData_Stream.sip index 57bdbdb5..1b64e7c8 100644 --- a/src/HYDROPy/HYDROData_Stream.sip +++ b/src/HYDROPy/HYDROData_Stream.sip @@ -146,6 +146,27 @@ public: * Removes all reference profile objects from stream. */ void RemoveProfiles(); + + /** + * Generates bottom polyline for stream or update the existing bottom polyline. + */ + bool GenerateBottomPolyline(); + + /** + * Returns reference bottom polyline object of stream. + */ + HYDROData_Polyline3D GetBottomPolyline() const + [Handle_HYDROData_Polyline3D ()]; + %MethodCode + Handle(HYDROData_Polyline3D) aRef; + + Py_BEGIN_ALLOW_THREADS + aRef = sipSelfWasArg ? sipCpp->HYDROData_Stream::GetBottomPolyline() : + sipCpp->GetBottomPolyline(); + Py_END_ALLOW_THREADS + + sipRes = (HYDROData_Polyline3D*)createPointer( aRef ); + %End protected: /** -- 2.39.2