Salome HOME
refs #524: draft implementation of "Recognize contours" operation.
[modules/hydro.git] / src / HYDROGUI / HYDROGUI_RecognizeContoursOp.cxx
1 // Copyright (C) 2014-2015  EDF-R&D
2 // This library is free software; you can redistribute it and/or
3 // modify it under the terms of the GNU Lesser General Public
4 // License as published by the Free Software Foundation; either
5 // version 2.1 of the License, or (at your option) any later version.
6 //
7 // This library is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10 // Lesser General Public License for more details.
11 //
12 // You should have received a copy of the GNU Lesser General Public
13 // License along with this library; if not, write to the Free Software
14 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15 //
16 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
17 //
18
19 #include "HYDROGUI_RecognizeContoursOp.h"
20
21 #include "HYDROGUI_RecognizeContoursDlg.h"
22 #include "HYDROGUI_Module.h"
23 #include "HYDROGUI_Shape.h"
24 #include "HYDROGUI_Tool.h"
25 #include "HYDROGUI_UpdateFlags.h"
26
27 #include <HYDROData_Document.h>
28 #include <HYDROData_GeomTool.h>
29 #include <HYDROData_ShapesTool.h>
30 #include <HYDROData_PolylineXY.h>
31
32 #include <GeometryGUI.h>
33 #include <GeometryGUI_Operations.h>
34 #include <GEOM_Constants.h>
35 #include <GEOMBase.h>
36
37 #include <OCCViewer_ViewManager.h>
38 #include <OCCViewer_ViewModel.h>
39
40 #include <SalomeApp_Study.h>
41
42 #include <LightApp_Application.h>
43 #include <LightApp_DataOwner.h>
44 #include <LightApp_Displayer.h>
45 #include <LightApp_SelectionMgr.h>
46
47 #include <SUIT_Desktop.h>
48 #include <SUIT_ViewManager.h>
49
50 #include <QDialog>
51 #include <QTemporaryFile>
52
53 /**
54   Constructor.
55 */
56 HYDROGUI_RecognizeContoursOp::HYDROGUI_RecognizeContoursOp( HYDROGUI_Module* theModule )
57 : HYDROGUI_Operation( theModule ),
58   myGEOMOpName( "" )
59 {
60   setName( tr( "CONTOURS_RECOGNITION" ) );
61 }
62
63 /**
64   Destructor.
65 */
66 HYDROGUI_RecognizeContoursOp::~HYDROGUI_RecognizeContoursOp()
67 {
68   cleanup();
69 }
70
71 /**
72 */
73 void HYDROGUI_RecognizeContoursOp::startOperation()
74 {
75   HYDROGUI_Operation::startOperation();
76   
77   // Get the selected image
78   myImage = Handle(HYDROData_Image)::DownCast( HYDROGUI_Tool::GetSelectedObject( module() ) );
79   if ( myImage.IsNull() ) {
80     abort();
81     return;
82   }
83
84   // Create temporary graphics file
85   QImage aQImage = myImage->Image();
86   myTmpImageFile = new QTemporaryFile( myImage->GetName() );
87   if ( !myTmpImageFile->open() || 
88        !aQImage.save( myTmpImageFile->fileName(), "PNG", 100 ) ) {
89     abort();
90     return;
91   }
92
93   // Create the input panel
94   HYDROGUI_RecognizeContoursDlg* aPanel = 
95     ::qobject_cast<HYDROGUI_RecognizeContoursDlg*>( inputPanel() );
96   if ( !aPanel ) {
97     return;
98   }
99
100   // Reset the panel
101   aPanel->reset();
102
103   // Get active study
104   SalomeApp_Study* aStudy = 
105     dynamic_cast<SalomeApp_Study*>( module()->getApp()->activeStudy() );
106
107   // Get active view manager
108   SUIT_ViewManager* aViewMgr = module()->getApp()->activeViewManager();
109
110   // Export the selected image to GEOM module
111   if ( aStudy && aViewMgr ) {
112     SALOMEDS::Study_var aDSStudy = GeometryGUI::ClientStudyToStudy( aStudy->studyDS() );
113     GEOM::GEOM_Gen_var aGeomEngine = GeometryGUI::GetGeomGen();
114
115     QString aGeomPictureEntry;
116
117     HYDROData_GeomTool::createFaceInGEOM( 
118       aGeomEngine, aDSStudy, aQImage.width(), aQImage.height(), myImage->GetName(), aGeomPictureEntry );
119     
120     if ( !aGeomPictureEntry.isEmpty() ) {
121       aStudy->setObjectProperty( aViewMgr->getGlobalId(), aGeomPictureEntry, 
122                                  GEOM::propertyName( GEOM::Texture ), myTmpImageFile->fileName() );
123     
124       // update the object browser
125       module()->getApp()->updateObjectBrowser( true );
126
127       // select the picture
128       SUIT_DataOwnerPtrList aList( true );
129       aList.append( SUIT_DataOwnerPtr( new LightApp_DataOwner( aGeomPictureEntry ) ) );
130       selectionMgr()->setSelected(aList );
131
132       // Add GEOM picture object entry to the list of temporary geom objects
133       myTmpGeomObjects << aGeomPictureEntry;
134     }
135   }
136
137   // Activate GEOM module operation
138   LightApp_Application* anApp = module()->getApp();
139   if ( anApp ) {
140     connect( anApp, SIGNAL( operationFinished( const QString&, const QString&, const QStringList& ) ), 
141              this, SLOT( onExternalOperationFinished( const QString&, const QString&, const QStringList& ) ) );
142
143     module()->getApp()->activateOperation( "Geometry", GEOMOp::OpFeatureDetect );
144   }
145 }
146
147 /**
148 */
149 void HYDROGUI_RecognizeContoursOp::abortOperation()
150 {
151   LightApp_Application* anApp = module()->getApp();
152   if ( anApp ) {
153     anApp->disconnect( this );
154   }
155
156   cleanup();
157
158   HYDROGUI_Operation::abortOperation();
159 }
160
161 /**
162 */
163 void HYDROGUI_RecognizeContoursOp::commitOperation()
164 {
165   cleanup();
166
167   HYDROGUI_Operation::commitOperation();
168 }
169
170 /**
171 */
172 bool HYDROGUI_RecognizeContoursOp::processApply( int& theUpdateFlags,
173                                                 QString& theErrorMsg,
174                                                 QStringList& theBrowseObjectsEntries )
175 {
176   // Get panel
177   HYDROGUI_RecognizeContoursDlg* aPanel = 
178     ::qobject_cast<HYDROGUI_RecognizeContoursDlg*>( inputPanel() );
179   if ( !aPanel ) {
180     return false;
181   }
182   
183   // Check if contour GEOM object exists
184   if ( myGeomContourEntry.isEmpty() ) {
185     theErrorMsg = tr( "NO_DETECTED_CONTOURS" );
186     return false;
187   }
188
189   // Create polylines
190   foreach ( QString aName, aPanel->getSelectedtPolylineNames() ) {
191     TopoDS_Shape aShape = myPolylineShapes.value( aName )->getTopoShape();
192     if ( aShape.IsNull() ) {
193       continue;
194     }
195
196     Handle(HYDROData_PolylineXY) aPolylineObj =
197       Handle(HYDROData_PolylineXY)::DownCast( doc()->CreateObject( KIND_POLYLINEXY ) );
198
199     if( !aPolylineObj.IsNull() ) {
200       aPolylineObj->SetName( aName );
201       aPolylineObj->ImportShape( aShape );
202       aPolylineObj->SetWireColor( HYDROData_PolylineXY::DefaultWireColor() );
203       aPolylineObj->Update();
204       module()->setIsToUpdate( aPolylineObj );
205     }
206   }
207   
208   theUpdateFlags = UF_Model;
209
210   return true;
211 }
212
213 /**
214 */
215 HYDROGUI_InputPanel* HYDROGUI_RecognizeContoursOp::createInputPanel() const
216 {
217   HYDROGUI_InputPanel* aPanel = new HYDROGUI_RecognizeContoursDlg( module(), getName() );
218
219   connect( aPanel, SIGNAL( selectionChanged( const QStringList& ) ), this, SLOT( onSelectionChanged( const QStringList& ) ) );
220
221   return aPanel;
222 }
223
224 /**
225  * Called when the operation perfomed by another module is finished.
226  * \param theModuleName the name of the module which perfomed the operation
227  * \param theOperationName the operation name
228  * \param theEntryList the list of the created objects entries
229  */
230 void HYDROGUI_RecognizeContoursOp::onExternalOperationFinished( 
231   const QString& theModuleName, const QString& theOperationName,
232   const QStringList& theEntryList )
233 {
234   // Process "Geometry" module operations only
235   if ( theModuleName != "Geometry" ) {
236     return;
237   }
238     
239   // Store the operation name
240   myGEOMOpName = theOperationName;
241
242   // Close the dialog corresponding to the external operation
243   closeExternalOperationDlg();
244   
245   // Erase the GEOM objects
246   LightApp_Displayer().Erase( theEntryList );
247
248   // Add GEOM object entries to the list of temporary GEOM objects
249   myTmpGeomObjects << theEntryList;
250
251   if ( theEntryList.count() == 1 ) {
252     myGeomContourEntry = theEntryList.first();
253
254     // Update the list of polylines
255     updateRecognizedPolylines();
256   }
257 }
258
259 /**
260   Close the GEOM contours detection dialog.
261 */
262 void HYDROGUI_RecognizeContoursOp::closeExternalOperationDlg()
263 {
264   if ( myGEOMOpName.isEmpty() ) {
265     return;
266   }
267
268   SUIT_Desktop* aDesktop = module()->getApp()->desktop();
269   if ( aDesktop ) {
270     QList<QDialog*> aDialogs = aDesktop->findChildren<QDialog*>();
271     foreach ( QDialog* aDlg, aDialogs ) {
272       if ( typeid(*aDlg).name() == myGEOMOpName ) {
273         aDlg->close();
274         break;
275       }
276     }
277   }
278 }
279
280 /**
281   Update the list of recognized polylines by exploding the GEOM contour object.
282 */
283 void HYDROGUI_RecognizeContoursOp::updateRecognizedPolylines()
284 {
285   // Erase the preview
286   erasePreview();
287
288   // Get active study
289   SalomeApp_Study* aStudy = 
290     dynamic_cast<SalomeApp_Study*>( module()->getApp()->activeStudy() );
291   if ( !aStudy ) {
292     return;
293   }
294
295   // Explode the compound
296   _PTR(SObject) aSObject( aStudy->studyDS()->FindObjectID( qPrintable( myGeomContourEntry ) ) );
297   if ( aSObject ) {
298     TopoDS_Shape aShape = GEOMBase::GetShapeFromIOR( aSObject->GetIOR().c_str() );
299
300     TopTools_SequenceOfShape aSubShapes;
301     HYDROData_ShapesTool::ExploreShapeToShapes( aShape, TopAbs_WIRE, aSubShapes );
302     if ( aSubShapes.Length() < 1 ) {
303       HYDROData_ShapesTool::ExploreShapeToShapes( aShape, TopAbs_EDGE, aSubShapes );
304     }
305
306     Handle(AIS_InteractiveContext) aCtx = NULL;
307
308     // Display preview
309     if ( !getPreviewManager() ) {
310       setPreviewManager( ::qobject_cast<OCCViewer_ViewManager*>( 
311                           module()->getApp()->getViewManager( OCCViewer_Viewer::Type(), true ) ) );
312     }
313
314     OCCViewer_ViewManager* aViewManager = getPreviewManager();
315     if ( aViewManager ) {
316       if ( OCCViewer_Viewer* aViewer = aViewManager->getOCCViewer() ) {
317         aCtx = aViewer->getAISContext();
318         connect( aViewer, SIGNAL( selectionChanged() ), this, SLOT( onViewerSelectionChanged() ) );
319       }
320     }
321
322     for ( int i = 1; i <= aSubShapes.Length(); i++ ) {
323       const TopoDS_Shape& aSubShape = aSubShapes.Value( i );
324
325       HYDROGUI_Shape* aShape = new HYDROGUI_Shape( aCtx, NULL, getPreviewZLayer() );
326       aShape->setShape( aSubShape, true, false );
327
328       QString aPrefix = QString("%1_%2_%3").arg( myImage->GetName(), "Contour", QString::number( i ) );
329       QString aName = HYDROGUI_Tool::GenerateObjectName( module(), aPrefix, QStringList(), true );
330       myPolylineShapes.insert( aName, aShape);
331     }
332
333     if ( !aCtx.IsNull() ) { //@MZN
334       aCtx->UpdateCurrentViewer();
335     }
336
337     // Get panel
338     HYDROGUI_RecognizeContoursDlg* aPanel = 
339       ::qobject_cast<HYDROGUI_RecognizeContoursDlg*>( inputPanel() );
340     if ( aPanel ) {
341       aPanel->setPolylineNames( myPolylineShapes.keys() );
342     }
343   }
344 }
345
346 /**
347   Erase the preview.
348 */
349 void HYDROGUI_RecognizeContoursOp::erasePreview()
350 {
351   foreach ( HYDROGUI_Shape* aShape, myPolylineShapes ) {
352     delete aShape;
353   }
354
355   myPolylineShapes.clear();
356 }
357
358 /**
359   Called when selection of the recognized polylines is changed.
360 */
361 void HYDROGUI_RecognizeContoursOp::onSelectionChanged( const QStringList& theSelectedNames )
362 {
363   foreach ( QString aName, myPolylineShapes.keys() ) {
364     bool isSelected = theSelectedNames.contains( aName );
365     myPolylineShapes[aName]->highlight( isSelected, true );
366   }
367 }
368
369 /**
370   Called when selection in the viewer is changed.
371 */
372 void HYDROGUI_RecognizeContoursOp::onViewerSelectionChanged()
373 {
374   // Get panel
375   HYDROGUI_RecognizeContoursDlg* aPanel = 
376     ::qobject_cast<HYDROGUI_RecognizeContoursDlg*>( inputPanel() );
377   if ( !aPanel ) {
378     return;
379   }
380
381   Handle(AIS_InteractiveContext) aCtx = NULL;
382
383   OCCViewer_ViewManager* aViewManager = getPreviewManager();
384   if ( aViewManager ) {
385     if ( OCCViewer_Viewer* aViewer = aViewManager->getOCCViewer() ) {
386       aCtx = aViewer->getAISContext();
387     }
388   }
389   
390   if ( !aCtx.IsNull() ) {
391     QStringList aSelectedNames;
392
393     foreach ( QString aName, myPolylineShapes.keys() ) {
394       bool isSelected = aCtx->IsSelected( myPolylineShapes[aName]->getAISObject() );
395       if ( isSelected ) {
396         aSelectedNames << aName;
397       }
398     }
399
400     aPanel->setSelectedPolylineNames( aSelectedNames );
401   }
402 }
403
404 /**
405   Do the operation data cleanup.
406 */
407 void HYDROGUI_RecognizeContoursOp::cleanup()
408 {
409   // Close the external operation dialog
410   closeExternalOperationDlg();
411
412   // Erase the preview 
413   erasePreview();
414
415   // Delete temporary image file
416   if ( myTmpImageFile ) {
417     delete myTmpImageFile;
418     myTmpImageFile = NULL;
419   }
420
421   // Delete temporary GEOM objects
422   if ( !myTmpGeomObjects.isEmpty() ) {
423     HYDROGUI_Tool::DeleteGeomObjects( module(), myTmpGeomObjects );
424     // update the object browser
425     module()->getApp()->updateObjectBrowser( true );
426   }
427 }