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