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