]> SALOME platform Git repositories - modules/hydro.git/blob - src/HYDROGUI/HYDROGUI_StreamOp.cxx
Salome HOME
Merge branch 'BR_IMPROVEMENTS' of ssh://git.salome-platform.org/modules/hydro into...
[modules/hydro.git] / src / HYDROGUI / HYDROGUI_StreamOp.cxx
1 // Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "HYDROGUI_StreamOp.h"
24
25 #include "HYDROGUI_Module.h"
26 #include <HYDROGUI_DataObject.h>
27 #include "HYDROGUI_Shape.h"
28 #include "HYDROGUI_StreamDlg.h"
29 #include "HYDROGUI_Tool.h"
30 #include "HYDROGUI_UpdateFlags.h"
31
32 #include <HYDROData_Document.h>
33 #include <HYDROData_PolylineXY.h>
34 #include <HYDROData_Profile.h>
35
36 #include <LightApp_Application.h>
37 #include <LightApp_SelectionMgr.h>
38 #include <LightApp_UpdateFlags.h>
39
40 #include <SUIT_MessageBox.h>
41 #include <SUIT_Desktop.h>
42
43 #include <OCCViewer_ViewManager.h>
44 #include <OCCViewer_ViewModel.h>
45 #include <OCCViewer_ViewWindow.h>
46 #include <gp_Ax1.hxx>
47 #include <gp_Ax2.hxx>
48 #include <gp_Ax3.hxx>
49 #include <gp_Vec.hxx>
50 #include <gp_Pnt.hxx>
51 #include <gp_Pln.hxx>
52 #include <gp.hxx>
53 #include <TopoDS_Face.hxx>
54 #include <TopoDS.hxx>
55 #include <BRepBuilderAPI_MakeFace.hxx>
56
57 void insertProfileInToOrder( const QString& theProfileName,
58                              const double&  theProfilePar,
59                              QStringList&   theProfiles,
60                              QList<double>& theProfileParams )
61 {
62   bool anIsInserted = false;
63   for ( int k = 0; k < theProfileParams.length(); ++k )
64   {
65     const double& aParam = theProfileParams.value( k );
66     if ( theProfilePar < aParam )
67     {
68       theProfiles.insert( k, theProfileName );
69       theProfileParams.insert( k, theProfilePar );
70       anIsInserted = true;
71       break;
72     }
73   }
74   
75   if ( !anIsInserted )
76   {
77     theProfiles << theProfileName;
78     theProfileParams << theProfilePar;
79   }
80 }
81
82 HYDROGUI_StreamOp::HYDROGUI_StreamOp( HYDROGUI_Module* theModule, bool theIsEdit )
83 : HYDROGUI_Operation( theModule ), 
84   myIsEdit( theIsEdit ),
85   myPreviewPrs( NULL )
86 {
87   setName( theIsEdit ? tr( "EDIT_STREAM" ) : tr( "CREATE_STREAM" ) );
88 }
89
90 HYDROGUI_StreamOp::~HYDROGUI_StreamOp()
91 {
92   erasePreview();
93 }
94
95 void HYDROGUI_StreamOp::startOperation()
96 {
97   HYDROGUI_Operation::startOperation();
98
99   if ( !myIsEdit || isApplyAndClose() )
100     myEditedObject.Nullify();
101   myHydAxis.clear();
102   myProfiles.clear();
103   myProfileParams.clear();
104
105   // Get panel and reset its state
106   HYDROGUI_StreamDlg* aPanel = (HYDROGUI_StreamDlg*)inputPanel();
107   aPanel->reset();
108
109   QString anObjectName = HYDROGUI_Tool::GenerateObjectName( module(), tr( "DEFAULT_STREAM_NAME" ) );
110   if ( myIsEdit )
111   {
112     if ( isApplyAndClose() )
113       myEditedObject =
114         Handle(HYDROData_Stream)::DownCast( HYDROGUI_Tool::GetSelectedObject( module() ) );
115     if ( !myEditedObject.IsNull() )
116     {
117       anObjectName = myEditedObject->GetName();
118
119       // Hydraulic axis
120       Handle(HYDROData_PolylineXY) aHydraulicAxis = myEditedObject->GetHydraulicAxis();
121       if ( !aHydraulicAxis.IsNull() )
122       {
123         myHydAxis = aHydraulicAxis->GetName();
124
125         TopoDS_Face aPlane;
126         if ( HYDROData_Stream::BuildFace( aHydraulicAxis, aPlane ) )
127         {
128           // Stream profiles
129           HYDROData_SequenceOfObjects aStreamProfiles = myEditedObject->GetProfiles();
130           for ( int i = 1, n = aStreamProfiles.Length(); i <= n; ++i )
131           {
132             Handle(HYDROData_Profile) aProfile = 
133               Handle(HYDROData_Profile)::DownCast( aStreamProfiles.Value( i ) );
134             if ( aProfile.IsNull() )
135               continue;
136
137             QString aProfileName = aProfile->GetName();
138
139             Standard_Real aProfilePar = 0.0;
140             HYDROData_Stream::HasIntersection( aHydraulicAxis, aProfile, aPlane, aProfilePar );
141
142             myProfiles      << aProfileName;
143             myProfileParams << aProfilePar;
144           }
145         }
146       }
147     }
148   }
149
150   // Update the panel
151   // set the edited object name
152   aPanel->setObjectName( anObjectName );
153
154   // set the existing 2D polylines names to the panel
155   aPanel->setAxisNames( HYDROGUI_Tool::FindExistingObjectsNames( doc(), KIND_POLYLINEXY ) );
156
157   // synchronize the panel state with the edited object state
158   updatePanelData();
159
160   // Create preview
161   createPreview();
162 }
163
164 void HYDROGUI_StreamOp::abortOperation()
165 {
166   erasePreview();
167   HYDROGUI_Operation::abortOperation();
168 }
169
170 void HYDROGUI_StreamOp::commitOperation()
171 {
172   erasePreview();
173   HYDROGUI_Operation::commitOperation();
174 }
175
176 HYDROGUI_InputPanel* HYDROGUI_StreamOp::createInputPanel() const
177 {
178   HYDROGUI_StreamDlg* aPanel = new HYDROGUI_StreamDlg( module(), getName() );
179
180   connect( aPanel, SIGNAL( AddProfiles() ), this, SLOT( onAddProfiles() ) );
181   connect( aPanel, SIGNAL( RemoveProfiles( const QStringList& ) ), 
182            this, SLOT( onRemoveProfiles( const QStringList& ) ) );
183   connect( aPanel, SIGNAL( AxisChanged( const QString& ) ), 
184            this, SLOT( onAxisChanged( const QString& ) ) );
185
186   return aPanel;
187 }
188
189 bool HYDROGUI_StreamOp::processApply( int& theUpdateFlags,
190                                       QString& theErrorMsg,
191                                       QStringList& theBrowseObjectsEntries )
192 {
193   HYDROGUI_StreamDlg* aPanel = ::qobject_cast<HYDROGUI_StreamDlg*>( inputPanel() );
194   if ( !aPanel )
195     return false;
196
197   // Check whether the object name is not empty
198   QString anObjectName = aPanel->getObjectName().simplified();
199   if ( anObjectName.isEmpty() )
200   {
201     theErrorMsg = tr( "INCORRECT_OBJECT_NAME" );
202     return false;
203   }
204
205   // Check that there are no other objects with the same name in the document
206   if ( !myIsEdit || ( !myEditedObject.IsNull() && myEditedObject->GetName() != anObjectName ) )
207   {
208     Handle(HYDROData_Entity) anObject = HYDROGUI_Tool::FindObjectByName( module(), anObjectName );
209     if( !anObject.IsNull() )
210     {
211       theErrorMsg = tr( "OBJECT_EXISTS_IN_DOCUMENT" ).arg( anObjectName );
212       return false;
213     }
214   }
215
216   if ( myEditedObject.IsNull() ) // Create new data model object
217     myEditedObject = Handle(HYDROData_Stream)::DownCast( doc()->CreateObject( KIND_STREAM ) );
218
219   // Check if the axis is set
220   Handle(HYDROData_PolylineXY) aHydAxis = Handle(HYDROData_PolylineXY)::DownCast(
221     HYDROGUI_Tool::FindObjectByName( module(), myHydAxis, KIND_POLYLINEXY ) );
222   if ( aHydAxis.IsNull() )
223   {
224     theErrorMsg = tr( "AXIS_NOT_DEFINED" );
225     return false;
226   }
227
228   // Check if at least 2 profiles is set
229   HYDROData_SequenceOfObjects aRefProfiles;
230   for ( int i = 0; i < myProfiles.length(); ++i )
231   {
232     QString aProfileName = myProfiles.value( i );
233
234     Handle(HYDROData_Profile) aProfile = Handle(HYDROData_Profile)::DownCast(
235       HYDROGUI_Tool::FindObjectByName( module(), aProfileName, KIND_PROFILE ) );
236     if ( !aProfile.IsNull() )
237       aRefProfiles.Append( aProfile );
238   }
239
240   if ( aRefProfiles.Length() < 2 )
241   {
242     theErrorMsg = tr( "PROFILES_NOT_DEFINED" );
243     return false;
244   }
245
246   // Set the object name
247   myEditedObject->SetName( anObjectName );
248
249   myEditedObject->SetHydraulicAxis( aHydAxis );
250   myEditedObject->SetProfiles( aRefProfiles, false );
251
252   if ( myEditedObject->IsMustBeUpdated() )
253     myEditedObject->Update();
254
255   if ( !myIsEdit )
256   {
257     myEditedObject->SetFillingColor( HYDROData_Stream::DefaultFillingColor() );
258     myEditedObject->SetBorderColor( HYDROData_Stream::DefaultBorderColor() );
259   }
260
261   // Erase preview
262   erasePreview();
263
264   // Show the object in case of creation mode of the operation
265   if( !myIsEdit ) {
266     module()->setObjectVisible( HYDROGUI_Tool::GetActiveOCCViewId( module() ), myEditedObject, true );
267     QString anEntry = HYDROGUI_DataObject::dataObjectEntry( myEditedObject );
268     theBrowseObjectsEntries.append( anEntry );
269   }
270
271   module()->setIsToUpdate( myEditedObject );
272
273   // Set update flags
274   theUpdateFlags = UF_Model | UF_OCCViewer | UF_OCC_Forced | UF_VTKViewer;
275
276   return true;
277 }
278
279 void HYDROGUI_StreamOp::createPreview()
280 {
281   LightApp_Application* anApp = module()->getApp();
282   if ( !getPreviewManager() )
283   {
284     setPreviewManager( ::qobject_cast<OCCViewer_ViewManager*>( 
285                        anApp->getViewManager( OCCViewer_Viewer::Type(), true ) ) );
286   }
287
288   OCCViewer_ViewManager* aViewManager = getPreviewManager();
289   if ( aViewManager && !myPreviewPrs )
290   {
291     if ( OCCViewer_Viewer* aViewer = aViewManager->getOCCViewer() )
292     {
293       Handle(AIS_InteractiveContext) aCtx = aViewer->getAISContext();
294       if ( !aCtx.IsNull() )
295       {
296         myPreviewPrs = new HYDROGUI_Shape( aCtx, NULL, getPreviewZLayer() );
297
298         QColor aFillingColor = HYDROData_Stream::DefaultFillingColor();
299         QColor aBorderColor = HYDROData_Stream::DefaultBorderColor();
300         if ( !myEditedObject.IsNull() )
301         {
302           aFillingColor = myEditedObject->GetFillingColor();
303           aBorderColor = myEditedObject->GetBorderColor();
304         }
305
306         myPreviewPrs->setFillingColor( aFillingColor, false, false );
307         myPreviewPrs->setBorderColor( aBorderColor, false, false );
308       }
309     }
310   }
311
312   if ( !aViewManager || !myPreviewPrs )
313     return;
314
315   Handle(HYDROData_PolylineXY) aHydAxis = Handle(HYDROData_PolylineXY)::DownCast(
316     HYDROGUI_Tool::FindObjectByName( module(), myHydAxis, KIND_POLYLINEXY ) );
317
318   HYDROData_SequenceOfObjects aRefProfiles;
319   for ( int i = 0; i < myProfiles.length(); ++i )
320   {
321     QString aProfileName = myProfiles.value( i );
322
323     Handle(HYDROData_Profile) aProfile = Handle(HYDROData_Profile)::DownCast(
324       HYDROGUI_Tool::FindObjectByName( module(), aProfileName, KIND_PROFILE ) );
325     if ( !aProfile.IsNull() )
326       aRefProfiles.Append( aProfile );
327   }
328
329   HYDROData_Stream::PrsDefinition aPrsDef;
330   if ( !HYDROData_Stream::CreatePresentations( aHydAxis, aRefProfiles, aPrsDef ) )
331   {
332     erasePreview();
333     return;
334   }
335
336   myPreviewPrs->setShape( aPrsDef.myPrs2D );
337 }
338
339 void HYDROGUI_StreamOp::erasePreview()
340 {
341   if( myPreviewPrs )
342   {
343     delete myPreviewPrs;
344     myPreviewPrs = 0;
345   }
346 }
347
348 void HYDROGUI_StreamOp::onAddProfiles()
349 {
350   Handle(HYDROData_PolylineXY) aHydAxis = Handle(HYDROData_PolylineXY)::DownCast(
351     HYDROGUI_Tool::FindObjectByName( module(), myHydAxis, KIND_POLYLINEXY ) );
352   if ( aHydAxis.IsNull() )
353     return;
354
355   TopoDS_Face aPlane;
356   if ( !HYDROData_Stream::BuildFace( aHydAxis, aPlane ) )
357     return;
358
359   // Get the current profiles list
360   QStringList aCurrentProfiles = myProfiles;
361     
362   // Get the selected profiles ( in the Object Browser )
363   QStringList anInvalidProfiles;
364   QStringList anExistingProfiles;
365   QStringList aHasNoIntersectionProfiles;
366   QStringList aVerifiedProfiles;
367
368   HYDROData_SequenceOfObjects aSelectedProfiles = HYDROGUI_Tool::GetSelectedObjects( module() ); 
369
370   for( int i = 1, n = aSelectedProfiles.Length(); i <= n; i++ )
371   {
372     Handle(HYDROData_Profile) aProfile = 
373       Handle(HYDROData_Profile)::DownCast( aSelectedProfiles.Value( i ) );
374     if ( aProfile.IsNull() )
375       continue;
376
377     QString aProfileName = aProfile->GetName();
378     Standard_Real aProfilePar = 0.0;
379
380     // Check the profile, if all is ok - add it to the list
381     if ( !aProfile->IsValid() )
382     {
383       // check whether the profile is valid
384       anInvalidProfiles << aProfileName;
385     }
386     else if ( aCurrentProfiles.contains( aProfileName ) )
387     {
388       // check whether the profile is already added
389       anExistingProfiles << aProfileName;
390     }
391     else if ( !HYDROData_Stream::HasIntersection( aHydAxis, aProfile, aPlane, aProfilePar ) )
392     {
393       // check whether the profile has intersection
394       aHasNoIntersectionProfiles << aProfileName;
395     }
396     else
397     {
398       // Insert profile in correct place
399       insertProfileInToOrder( aProfileName, aProfilePar, myProfiles, myProfileParams );
400       aVerifiedProfiles << aProfileName;
401     }
402   }
403  
404   // Show message box with the ignored profiles
405   if ( !anInvalidProfiles.isEmpty() ||
406        !anExistingProfiles.isEmpty() ||
407        !aHasNoIntersectionProfiles.isEmpty() )
408   {
409     QString aMessage = tr( "IGNORED_PROFILES" );
410     if ( !anInvalidProfiles.isEmpty() )
411     {
412       aMessage.append( "\n\n" );
413       aMessage.append( tr("INVALID_PROFILES").arg( anInvalidProfiles.join( "\n" ) ) );
414     }
415     if ( !anExistingProfiles.isEmpty() )
416     {
417       aMessage.append( "\n\n" );
418       aMessage.append( tr("EXISTING_PROFILES").arg( anExistingProfiles.join( "\n" ) ) );
419     }
420     if ( !aHasNoIntersectionProfiles.isEmpty() )
421     {
422       aMessage.append( "\n\n" );
423       aMessage.append( tr("NOT_INTERSECTED_PROFILES").arg( aHasNoIntersectionProfiles.join( "\n" ) ) );
424     }
425
426     SUIT_MessageBox::warning( module()->getApp()->desktop(), tr( "WARNING" ), aMessage );
427   }
428
429   if ( aVerifiedProfiles.isEmpty() )
430     return;
431
432   // Update the panel
433   updatePanelData();
434
435   // Update preview
436   createPreview();
437 }
438
439 void HYDROGUI_StreamOp::onRemoveProfiles( const QStringList& theProfilesToRemove )
440 {
441   QStringList aToRemove = theProfilesToRemove;
442
443   // Take the Object Browser selection into account
444   HYDROData_SequenceOfObjects aSelectedObjects = HYDROGUI_Tool::GetSelectedObjects( module() ); 
445   for( int i = 1, n = aSelectedObjects.Length(); i <= n; i++ )
446   {
447     Handle(HYDROData_Profile) aProfile = 
448       Handle(HYDROData_Profile)::DownCast( aSelectedObjects.Value( i ) );
449     if ( aProfile.IsNull() )
450       continue;
451
452     QString aProfileName = aProfile->GetName();
453     aToRemove.append( aProfileName );
454   }
455
456   aToRemove.removeDuplicates();
457   if ( aToRemove.isEmpty() )
458     return;
459
460   bool isRemoved = false;
461
462   // Remove profiles
463   for ( int i = 0; i < aToRemove.length(); ++i )
464   {
465     const QString& aProfileName = aToRemove.value( i );
466
467     int aProfileId = myProfiles.indexOf( aProfileName );
468     if ( aProfileId < 0 )
469       continue;
470
471     myProfiles.removeAt( aProfileId );
472     myProfileParams.removeAt( aProfileId );
473     isRemoved = true;
474   }
475
476   if ( isRemoved )
477   {
478     // Update the panel
479     updatePanelData();
480
481     // Update preview
482     createPreview();
483   }
484 }
485
486 void HYDROGUI_StreamOp::onAxisChanged( const QString& theNewAxis )
487 {
488   // Get axis object   
489   Handle(HYDROData_PolylineXY) aNewAxis = Handle(HYDROData_PolylineXY)::DownCast(
490     HYDROGUI_Tool::FindObjectByName( module(), theNewAxis, KIND_POLYLINEXY ) );
491
492   // Prepare data for intersection check
493   TopoDS_Face aPlane;
494   if ( !HYDROData_Stream::BuildFace( aNewAxis, aPlane ) )
495   {
496     SUIT_MessageBox::critical( module()->getApp()->desktop(), 
497                               tr( "BAD_SELECTED_POLYLINE_TLT" ),
498                               tr( "BAD_SELECTED_POLYLINE_MSG" ).arg( theNewAxis ) );
499     // To restore the old axis
500     updatePanelData();
501     return;
502   }
503
504   QStringList   aNewProfiles;
505   QList<double> aNewProfileParams;
506   QStringList   aHasNoIntersectionProfiles;
507
508   // Get list of profiles which do not intersect the axis
509   for ( int i = 0; i < myProfiles.length(); ++i )
510   {
511     QString aProfileName = myProfiles.value( i );
512
513     Handle(HYDROData_Profile) aProfile = Handle(HYDROData_Profile)::DownCast(
514       HYDROGUI_Tool::FindObjectByName( module(), aProfileName, KIND_PROFILE ) );
515     if ( aProfile.IsNull() )
516       continue;
517       
518     Standard_Real aProfilePar = 0.0;
519     if ( HYDROData_Stream::HasIntersection( aNewAxis, aProfile, aPlane, aProfilePar ) )
520     {
521       // Insert profile in correct place
522       insertProfileInToOrder( aProfileName, aProfilePar, aNewProfiles, aNewProfileParams );
523     }
524     else
525     {
526       aHasNoIntersectionProfiles << aProfile->GetName();
527     }
528   }
529
530   // If there are profiles which don't intersect the new axis - show confirmation message box
531   bool isConfirmed = true;
532   if ( !aHasNoIntersectionProfiles.isEmpty() )
533   {
534     SUIT_MessageBox::StandardButtons aButtons = 
535       SUIT_MessageBox::Yes | SUIT_MessageBox::No;
536
537     QString aMsg = aHasNoIntersectionProfiles.join( "\n" );
538     isConfirmed = SUIT_MessageBox::question( module()->getApp()->desktop(),
539                                              tr( "CONFIRMATION" ),
540                                              tr( "CONFIRM_AXIS_CHANGE" ).arg( aMsg ),
541                                              aButtons, 
542                                              SUIT_MessageBox::Yes) == SUIT_MessageBox::Yes;
543   }
544
545   // Check if the user has confirmed axis change
546   if ( !isConfirmed )
547   {
548     // To restore the old axis
549     updatePanelData();
550   }
551   else
552   {
553     // Update data
554     myHydAxis = theNewAxis;
555     myProfiles = aNewProfiles;
556     myProfileParams = aNewProfileParams;
557
558     // Update the panel
559     updatePanelData();
560
561     // Update preview
562     createPreview();
563   }
564 }
565
566 void HYDROGUI_StreamOp::updatePanelData()
567 {
568   HYDROGUI_StreamDlg* aPanel = ::qobject_cast<HYDROGUI_StreamDlg*>( inputPanel() );
569   if ( !aPanel )
570     return;
571
572   aPanel->setAxisName( myHydAxis );
573   aPanel->setProfiles( myProfiles );
574 }