Salome HOME
a3166c19372857cd137d367de2755f49384b8678
[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 #include "HYDROGUI_OCCSelector.h"
27 #include "HYDROGUI_ZLayers.h" //@MZN
28
29 #include <HYDROData_Document.h>
30 #include <HYDROData_GeomTool.h>
31 #include <HYDROData_ShapesTool.h>
32 #include <HYDROData_PolylineXY.h>
33
34 #include <GeometryGUI.h>
35 #include <GeometryGUI_Operations.h>
36 #include <GEOM_Constants.h>
37 #include <GEOMBase.h>
38
39 #include <OCCViewer_ViewManager.h>
40 #include <OCCViewer_ViewModel.h>
41
42 #include <SalomeApp_Study.h>
43
44 #include <LightApp_Application.h>
45 #include <LightApp_DataOwner.h>
46 #include <LightApp_Displayer.h>
47 #include <LightApp_SelectionMgr.h>
48
49 #include <SUIT_Desktop.h>
50 #include <SUIT_ViewManager.h>
51
52 #include <BRepBuilderAPI_GTransform.hxx>
53 #include <gp_GTrsf.hxx>
54
55 #include <QDialog>
56 #include <QTemporaryFile>
57
58 /**
59   Constructor.
60 */
61 HYDROGUI_RecognizeContoursOp::HYDROGUI_RecognizeContoursOp( HYDROGUI_Module* theModule )
62 : HYDROGUI_Operation( theModule ),
63   myGEOMOpName( "" )
64 {
65   setName( tr( "CONTOURS_RECOGNITION" ) );
66 }
67
68 /**
69   Destructor.
70 */
71 HYDROGUI_RecognizeContoursOp::~HYDROGUI_RecognizeContoursOp()
72 {
73   cleanup();
74 }
75
76 /**
77 */
78 void HYDROGUI_RecognizeContoursOp::startOperation()
79 {
80   HYDROGUI_Operation::startOperation();
81   
82   if ( !isApplyAndClose() ) {
83     return;
84   }
85
86   // Get the selected image
87   myImage = Handle(HYDROData_Image)::DownCast( HYDROGUI_Tool::GetSelectedObject( module() ) );
88   if ( myImage.IsNull() ) {
89     abort();
90     return;
91   }
92   QString anImageName = myImage->GetName();
93
94   // Create temporary graphics file
95   QImage aQImage = myImage->Image();
96   myTmpImageFile = new QTemporaryFile( anImageName );
97   if ( !myTmpImageFile->open() || 
98        !aQImage.save( myTmpImageFile->fileName(), "PNG", 100 ) ) {
99     abort();
100     return;
101   }
102
103   // Create the input panel
104   HYDROGUI_RecognizeContoursDlg* aPanel = 
105     ::qobject_cast<HYDROGUI_RecognizeContoursDlg*>( inputPanel() );
106   if ( !aPanel ) {
107     return;
108   }
109
110   // Reset the panel
111   aPanel->reset();
112   aPanel->setImageName( anImageName );
113
114   // Get active study
115   SalomeApp_Study* aStudy = 
116     dynamic_cast<SalomeApp_Study*>( module()->getApp()->activeStudy() );
117
118   // Get active view manager
119   SUIT_ViewManager* aViewMgr = module()->getApp()->activeViewManager();
120
121   // Export the selected image to GEOM module
122   if ( aStudy && aViewMgr ) {
123     SALOMEDS::Study_var aDSStudy = GeometryGUI::ClientStudyToStudy( aStudy->studyDS() );
124     GEOM::GEOM_Gen_var aGeomEngine = GeometryGUI::GetGeomGen();
125
126     QString aGeomPictureEntry;
127
128     HYDROData_GeomTool::createFaceInGEOM( aGeomEngine, aDSStudy, aQImage.width(), aQImage.height(), 
129                                           anImageName, aGeomPictureEntry );
130     
131     if ( !aGeomPictureEntry.isEmpty() ) {
132       aStudy->setObjectProperty( aViewMgr->getGlobalId(), aGeomPictureEntry, 
133                                  GEOM::propertyName( GEOM::Texture ), myTmpImageFile->fileName() );
134     
135       // update the object browser
136       module()->getApp()->updateObjectBrowser( true );
137
138       // select the picture
139       SUIT_DataOwnerPtrList aList( true );
140       aList.append( SUIT_DataOwnerPtr( new LightApp_DataOwner( aGeomPictureEntry ) ) );
141       selectionMgr()->setSelected(aList );
142
143       // Add GEOM picture object entry to the list of temporary geom objects
144       myTmpGeomObjects << aGeomPictureEntry;
145     }
146   }
147
148   // Activate GEOM module operation
149   LightApp_Application* anApp = module()->getApp();
150   if ( anApp ) {
151     connect( anApp, SIGNAL( operationFinished( const QString&, const QString&, const QStringList& ) ), 
152              this, SLOT( onExternalOperationFinished( const QString&, const QString&, const QStringList& ) ) );
153
154     module()->getApp()->activateOperation( "Geometry", GEOMOp::OpFeatureDetect );
155   }
156 }
157
158 /**
159 */
160 void HYDROGUI_RecognizeContoursOp::abortOperation()
161 {
162   LightApp_Application* anApp = module()->getApp();
163   if ( anApp ) {
164     anApp->disconnect( this );
165   }
166
167   cleanup();
168
169   HYDROGUI_Operation::abortOperation();
170 }
171
172 /**
173 */
174 void HYDROGUI_RecognizeContoursOp::commitOperation()
175 {
176   if ( isApplyAndClose() ) {
177     cleanup();
178   }
179
180   HYDROGUI_Operation::commitOperation();
181 }
182
183 /**
184 */
185 bool HYDROGUI_RecognizeContoursOp::processApply( int& theUpdateFlags,
186                                                 QString& theErrorMsg,
187                                                 QStringList& theBrowseObjectsEntries )
188 {
189   // Check the original image
190   if ( myImage.IsNull() ) {
191     return false;
192   }
193
194   // Get panel
195   HYDROGUI_RecognizeContoursDlg* aPanel = 
196     ::qobject_cast<HYDROGUI_RecognizeContoursDlg*>( inputPanel() );
197   if ( !aPanel ) {
198     return false;
199   }
200   
201   // Check if contour GEOM object exists
202   if ( myGeomContourEntry.isEmpty() ) {
203     theErrorMsg = tr( "NO_DETECTED_CONTOURS" );
204     return false;
205   }
206
207   // Get selected polylines
208   QStringList aSelectedtPolylines = aPanel->getSelectedtPolylineNames();
209   // Remove the selected polylines from the panel
210   aPanel->removePolylineNames( aSelectedtPolylines );
211
212   // Create polylines
213   foreach ( QString aName, aSelectedtPolylines ) {
214     TopoDS_Shape aShape = myPolylineShapes.value( aName )->getTopoShape();
215     if ( aShape.IsNull() ) {
216       continue;
217     }
218
219     Handle(HYDROData_PolylineXY) aPolylineObj =
220       Handle(HYDROData_PolylineXY)::DownCast( doc()->CreateObject( KIND_POLYLINEXY ) );
221
222     if( !aPolylineObj.IsNull() ) {
223       aPolylineObj->SetName( aName );
224       aPolylineObj->ImportShape( aShape );
225       aPolylineObj->SetWireColor( HYDROData_PolylineXY::DefaultWireColor() );
226
227       aPolylineObj->Update();
228       module()->setIsToUpdate( aPolylineObj );
229     }
230
231     // Remove the shape from the map
232     HYDROGUI_Shape* aShapeToDelete = myPolylineShapes.take( aName );
233     delete aShapeToDelete;
234   }
235  
236   theUpdateFlags = UF_Model;
237
238   return true;
239 }
240
241 /**
242 */
243 HYDROGUI_InputPanel* HYDROGUI_RecognizeContoursOp::createInputPanel() const
244 {
245   HYDROGUI_InputPanel* aPanel = new HYDROGUI_RecognizeContoursDlg( module(), getName() );
246
247   connect( aPanel, SIGNAL( selectionChanged( const QStringList& ) ), this, SLOT( onSelectionChanged( const QStringList& ) ) );
248
249   return aPanel;
250 }
251
252 /**
253  * Called when the operation perfomed by another module is finished.
254  * \param theModuleName the name of the module which perfomed the operation
255  * \param theOperationName the operation name
256  * \param theEntryList the list of the created objects entries
257  */
258 void HYDROGUI_RecognizeContoursOp::onExternalOperationFinished( 
259   const QString& theModuleName, const QString& theOperationName,
260   const QStringList& theEntryList )
261 {
262   // Process "Geometry" module operations only
263   if ( theModuleName != "Geometry" ) {
264     return;
265   }
266     
267   // Store the operation name
268   myGEOMOpName = theOperationName;
269
270   // Close the dialog corresponding to the external operation
271   closeExternalOperationDlg();
272   
273   // Erase the GEOM objects
274   LightApp_Displayer().Erase( theEntryList );
275
276   // Add GEOM object entries to the list of temporary GEOM objects
277   myTmpGeomObjects << theEntryList;
278
279   if ( theEntryList.count() == 1 ) {
280     myGeomContourEntry = theEntryList.first();
281
282     // Update the list of polylines
283     updateRecognizedPolylines();
284   }
285 }
286
287 /**
288   Close the GEOM contours detection dialog.
289 */
290 void HYDROGUI_RecognizeContoursOp::closeExternalOperationDlg()
291 {
292   if ( myGEOMOpName.isEmpty() ) {
293     return;
294   }
295
296   SUIT_Desktop* aDesktop = module()->getApp()->desktop();
297   if ( aDesktop ) {
298     QList<QDialog*> aDialogs = aDesktop->findChildren<QDialog*>();
299     foreach ( QDialog* aDlg, aDialogs ) {
300       if ( typeid(*aDlg).name() == myGEOMOpName ) {
301         aDlg->close();
302         break;
303       }
304     }
305   }
306 }
307
308 /**
309   Update the list of recognized polylines by exploding the GEOM contour object.
310 */
311 void HYDROGUI_RecognizeContoursOp::updateRecognizedPolylines()
312 {
313   // Erase the preview
314   erasePreview();
315
316   // Get active study
317   SalomeApp_Study* aStudy = 
318     dynamic_cast<SalomeApp_Study*>( module()->getApp()->activeStudy() );
319   if ( !aStudy ) {
320     return;
321   }
322
323   // Explode the compound
324   _PTR(SObject) aSObject( aStudy->studyDS()->FindObjectID( qPrintable( myGeomContourEntry ) ) );
325   if ( aSObject ) {
326     TopoDS_Shape aShape = GEOMBase::GetShapeFromIOR( aSObject->GetIOR().c_str() );
327
328     TopTools_SequenceOfShape aSubShapes;
329     HYDROData_ShapesTool::ExploreShapeToShapes( aShape, TopAbs_WIRE, aSubShapes );
330     if ( aSubShapes.Length() < 1 ) {
331       HYDROData_ShapesTool::ExploreShapeToShapes( aShape, TopAbs_EDGE, aSubShapes );
332     }
333
334     Handle(AIS_InteractiveContext) aCtx = NULL;
335
336     // Display preview
337     if ( !getPreviewManager() ) {
338       setPreviewManager( ::qobject_cast<OCCViewer_ViewManager*>( 
339                           module()->getApp()->getViewManager( OCCViewer_Viewer::Type(), true ) ) );
340     }
341
342     OCCViewer_ViewManager* aViewManager = getPreviewManager();
343     if ( aViewManager ) {
344       if ( OCCViewer_Viewer* aViewer = aViewManager->getOCCViewer() ) {
345         // aViewer->enablePreselection( true );
346         // aViewer->enableSelection( true );
347         aCtx = aViewer->getAISContext();
348         connect( aViewer, SIGNAL( selectionChanged() ), this, SLOT( onViewerSelectionChanged() ) );
349       }
350     }
351
352     QTransform aTrsf = myImage->Trsf();
353     QImage anImage = myImage->Image();
354     QRectF aRect( QPointF( 0, 0 ), QPointF( anImage.width(), anImage.height() ) );
355     aRect = aTrsf.mapRect( aRect );
356     aTrsf.setMatrix( aTrsf.m11(), aTrsf.m12(),  aTrsf.m13(),
357                      aTrsf.m21(), -aTrsf.m22(), aTrsf.m23(),
358                      aTrsf.m31() + aRect.width() * 0.5, aTrsf.m32 () - aRect.height() * 0.5, aTrsf.m33() );
359
360     /* @MZN
361     QTransform aTrsf = myImage->Trsf();
362     gp_Mat aMat( aTrsf.m11(), aTrsf.m21(), 0, 
363                  aTrsf.m12(), -aTrsf.m22(), 0, 
364                  0,           0,           1 );
365     QImage anImage = myImage->Image();
366     QRectF aRect( QPointF( 0, 0 ), QPointF( anImage.width(), anImage.height() ) );
367     aRect = aTrsf.mapRect( aRect );
368     gp_XYZ aVec( aTrsf.m31() + aRect.width() * 0.5, 
369                  aTrsf.m32() - aRect.height() * 0.5, 0 );
370
371     BRepBuilderAPI_GTransform aBuilder( gp_GTrsf( aMat, aVec ) );
372     */
373
374     Handle(HYDROData_PolylineXY) aPolylineObj = Handle(HYDROData_PolylineXY)::DownCast( doc()->CreateObject( KIND_POLYLINEXY ) );
375     QStringList aNamesList;
376     for ( int i = 1; i <= aSubShapes.Length(); i++ ) {
377       TopoDS_Shape aSubShape = aSubShapes.Value( i );
378
379       // Transform the sub-shape
380       aPolylineObj->ImportShape( aSubShape );
381       aPolylineObj->Transform( aTrsf );
382
383       /*
384       aBuilder.Perform( aSubShape, Standard_True );
385       if ( aBuilder.IsDone() ) {
386         aSubShape = aBuilder.Shape();
387       }*/
388       
389       HYDROGUI_Shape* aShape = new HYDROGUI_Shape( aCtx, NULL, getPreviewZLayer() );
390       aShape->setShape( aPolylineObj->GetShape(), true, false );
391       aShape->setBorderColor( HYDROData_PolylineXY::DefaultWireColor(), false, false );
392       
393       QString aPrefix = QString("%1_%2_%3").arg( myImage->GetName(), "Contour", QString::number( i ) );
394       QString aName = HYDROGUI_Tool::GenerateObjectName( module(), aPrefix, QStringList(), true );
395       myPolylineShapes.insert( aName, aShape);
396       aNamesList << aName;
397     }
398
399     aPolylineObj->Remove();
400
401     if ( !aCtx.IsNull() ) {
402       UpdateZLayersOfHilightPresentationsOfDisplayedObjects( aCtx, Graphic3d_ZLayerId_TopOSD );
403       aCtx->UpdateCurrentViewer();
404     }
405
406     // Get panel
407     HYDROGUI_RecognizeContoursDlg* aPanel = 
408       ::qobject_cast<HYDROGUI_RecognizeContoursDlg*>( inputPanel() );
409     if ( aPanel ) {
410       aPanel->setPolylineNames( aNamesList );
411     }
412   }
413 }
414
415 /**
416   Erase the preview.
417 */
418 void HYDROGUI_RecognizeContoursOp::erasePreview()
419 {
420   foreach ( HYDROGUI_Shape* aShape, myPolylineShapes ) {
421     delete aShape;
422   }
423
424   myPolylineShapes.clear();
425 }
426
427 /**
428   Called when selection of the recognized polylines is changed.
429 */
430 void HYDROGUI_RecognizeContoursOp::onSelectionChanged( const QStringList& theSelectedNames )
431 {
432   Handle(AIS_InteractiveContext) aCtx = NULL;
433
434   OCCViewer_ViewManager* aViewManager = getPreviewManager();
435   if ( aViewManager ) {
436     if ( OCCViewer_Viewer* aViewer = aViewManager->getOCCViewer() ) {
437       aCtx = aViewer->getAISContext();
438     }
439   }
440
441   if ( !aCtx.IsNull() ) {
442     foreach ( QString aName, myPolylineShapes.keys() ) {
443       Handle(AIS_InteractiveObject) anObject = 
444         myPolylineShapes.value(aName)->getAISObject();
445
446       bool isSelected = theSelectedNames.contains( aName );
447       if ( ( isSelected && !aCtx->IsSelected( anObject) ) ||
448            ( !isSelected && aCtx->IsSelected( anObject) ) ) {
449         aCtx->AddOrRemoveSelected( anObject, Standard_False );
450       }
451       // myPolylineShapes[aName]->highlight( isSelected, true );
452     }
453     aCtx->UpdateCurrentViewer();
454   }
455 }
456
457 /**
458   Called when selection in the viewer is changed.
459 */
460 void HYDROGUI_RecognizeContoursOp::onViewerSelectionChanged()
461 {
462   // Get panel
463   HYDROGUI_RecognizeContoursDlg* aPanel = 
464     ::qobject_cast<HYDROGUI_RecognizeContoursDlg*>( inputPanel() );
465   if ( !aPanel ) {
466     return;
467   }
468
469   Handle(AIS_InteractiveContext) aCtx = NULL;
470
471   OCCViewer_ViewManager* aViewManager = getPreviewManager();
472   if ( aViewManager ) {
473     if ( OCCViewer_Viewer* aViewer = aViewManager->getOCCViewer() ) {
474       aCtx = aViewer->getAISContext();
475     }
476   }
477   
478   if ( !aCtx.IsNull() ) {
479     QStringList aSelectedNames;
480
481     foreach ( QString aName, myPolylineShapes.keys() ) {
482       bool isSelected = aCtx->IsSelected( myPolylineShapes.value(aName)->getAISObject() );
483       if ( isSelected ) {
484         aSelectedNames << aName;
485       }
486     }
487
488     aPanel->setSelectedPolylineNames( aSelectedNames );
489   }
490 }
491
492 /**
493   Do the operation data cleanup.
494 */
495 void HYDROGUI_RecognizeContoursOp::cleanup()
496 {
497   // Close the external operation dialog
498   closeExternalOperationDlg();
499
500   // Erase the preview 
501   erasePreview();
502
503   // Delete temporary image file
504   if ( myTmpImageFile ) {
505     delete myTmpImageFile;
506     myTmpImageFile = NULL;
507   }
508
509   // Delete temporary GEOM objects
510   if ( !myTmpGeomObjects.isEmpty() ) {
511     HYDROGUI_Tool::DeleteGeomObjects( module(), myTmpGeomObjects );
512     // update the object browser
513     module()->getApp()->updateObjectBrowser( true );
514   }
515 }