]> SALOME platform Git repositories - modules/geom.git/blob - src/EntityGUI/EntityGUI_FeatureDetectorDlg.cxx
Salome HOME
0023055: EDF 10725 GEOM: In the shape recognition functionality, it is not possible...
[modules/geom.git] / src / EntityGUI / EntityGUI_FeatureDetectorDlg.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 // GEOM GEOMGUI : GUI for Geometry component
24 // File   : EntityGUI_SketcherDlg.cxx
25 // Author : Renaud NEDELEC, Open CASCADE S.A.S.
26
27 // SALOME includes
28 #include "EntityGUI_FeatureDetectorDlg.h"
29 #include "ShapeRec_FeatureDetector.hxx"
30 #include "GEOM_Constants.h"
31
32 #include <OCCViewer_ViewWindow.h>
33 #include <OCCViewer_ViewManager.h>
34
35 #include <SOCC_ViewModel.h>
36
37 #include <DlgRef.h>
38 #include <GeometryGUI.h>
39 #include <EntityGUI.h>
40 #include <GEOMBase.h>
41
42 #include <SUIT_Desktop.h>
43 #include <SUIT_ResourceMgr.h>
44 #include <SUIT_Session.h>
45 #include <SUIT_ViewWindow.h>
46 #include <SalomeApp_Application.h>
47 #include <LightApp_Application.h>
48 #include <LightApp_SelectionMgr.h>
49
50 #include <SALOME_ListIO.hxx>
51
52 #include <SalomeApp_Study.h>
53
54 #include <utilities.h>
55 #include <Precision.hxx>
56
57 // OCCT includes
58 #include <gp_Pnt.hxx>
59 #include <TopoDS_Shape.hxx>
60 #include <TopoDS_Wire.hxx>
61
62 #include <BRepBuilderAPI_MakeVertex.hxx>
63 #include <BRepBuilderAPI_MakeFace.hxx>
64 #include <BRepBuilderAPI_MakePolygon.hxx>
65 #include <BRepBuilderAPI_Transform.hxx>
66
67 #include <AIS_TexturedShape.hxx>
68 #include <TCollection_AsciiString.hxx>
69 #include <StdSelect_DisplayMode.hxx>
70
71 #include <Graphic3d_MaterialAspect.hxx>
72
73 // C++ includes
74 #include <set>
75 #include <utility>
76
77 // boost includes
78 #include <boost/utility.hpp>
79
80 // Constructors
81 enum{
82   CONTOURS,
83   CORNERS,
84   LINES
85 };
86
87 enum {
88   KERNEL_SIZE,
89   FIND_CONTOURS_METHOD,
90   QUALITY_LEVEL,
91   MIN_DISTANCE,
92   TYPE_CRITERIA,
93   MAX_ITER,
94   EPSILON,
95   LOW_THRESHOLD,
96   RATIO,
97   L2GRADIENT,
98   SMOOTH_SIZE,
99   HBINS,
100   SBINS,
101   HIST_TYPE,
102   THRESHOLD_VALUE,
103   MAX_THRESHOLD,
104 };
105
106 // // // View
107 // // enum {
108 // //   XY,
109 // //   YZ,
110 // //   XZ
111 // // };
112   
113
114 //=================================================================================
115 // class    : EntityGUI_FeatureDetectorDlg()
116 // purpose  : Constructs a EntityGUI_FeatureDetectorDlg which is a child of 'parent', with the
117 //            name 'name' and widget flags set to 'f'.
118 //            The dialog will by default be modeless, unless you set 'modal' to
119 //            TRUE to construct a modal dialog.
120 //=================================================================================
121 EntityGUI_FeatureDetectorDlg::EntityGUI_FeatureDetectorDlg( GeometryGUI* theGeometryGUI, QWidget* parent,
122                                               bool modal, Qt::WindowFlags fl)
123   : GEOMBase_Skeleton(theGeometryGUI, parent, modal, fl) 
124 {
125   QPixmap image0(SUIT_Session::session()->resourceMgr()->loadPixmap("GEOM", tr("ICON_SELECT")));
126   QPixmap image1(SUIT_Session::session()->resourceMgr()->loadPixmap("OCCViewer", tr("ICON_OCCVIEWER_VIEW_DUMP")));
127
128   setWindowTitle(tr("GEOM_DETECT_TITLE"));
129   
130   /***************************************************************/
131   
132   mainFrame()->GroupConstructors->setTitle(tr("GEOM_FEATURES"));
133   mainFrame()->RadioButton1->setText(tr("GEOM_CONTOURS"));
134   mainFrame()->RadioButton2->setText(tr("GEOM_CORNERS"));
135   mainFrame()->RadioButton3->setAttribute(Qt::WA_DeleteOnClose);
136   mainFrame()->RadioButton3->close();
137   
138 //   myViewGroup = new DlgRef_3Radio(centralWidget());
139 //   myViewGroup->GroupBox1->setTitle(tr("GEOM_VIEW"));
140 //   myViewGroup->RadioButton1->setText(tr( "GEOM_TOP"  ));
141 //   myViewGroup->RadioButton2->setText(tr( "GEOM_FRONT"));
142 //   myViewGroup->RadioButton3->setText(tr( "GEOM_LEFT" ));
143 //   myViewButtonGroup = new QButtonGroup( this );
144 //   myViewButtonGroup->addButton( myViewGroup->RadioButton1, XY ); // Top view
145 //   myViewButtonGroup->addButton( myViewGroup->RadioButton2, YZ ); // Front View
146 //   myViewButtonGroup->addButton( myViewGroup->RadioButton3, XZ ); // Left View
147 //   
148 //   myViewGroup->hide();
149   
150   // Widgets for the selection of the picture and the Region Of Interest 
151   
152   
153   mySelectionGroup = new DlgRef_1Sel1Frame(centralWidget());
154
155   mySelectionGroup->PushButton1->setIcon(image0);
156   mySelectionGroup->PushButton1->setCheckable(true);
157   mySelectionGroup->PushButton1->setAutoExclusive(true);
158   
159   mySelectionGroup->PushButton2->setIcon(image1);
160   mySelectionGroup->PushButton2->setCheckable(true);
161   mySelectionGroup->PushButton2->setAutoExclusive(true);
162
163   mySelectionGroup->TextLabel1->setText(tr( "GEOM_PICTURE" ));
164   mySelectionGroup->FrameLabel->setText("");
165   
166   myOutputGroup = new DlgRef_3Radio(centralWidget());
167   myOutputGroup->GroupBox1->setTitle(tr("GEOM_DETECT_OUTPUT"));
168   myOutputGroup->RadioButton2->setText(tr( "GEOM_POLYLINE"  ));
169   myOutputGroup->RadioButton1->setText(tr( "GEOM_SPLINE"));
170   myOutputGroup->RadioButton3->hide();
171   
172 //   myOutputGroup->hide(); //caché pour la demo
173     
174   // Parameters 
175   QGridLayout* parametersLayout = new QGridLayout();
176   parametersLayout->setMargin(9);
177   QComboBox* kernelSize = new QComboBox();
178   kernelSize->addItems( QStringList() << "3" << "5" << "7" );
179   myWidgets.insert( KERNEL_SIZE, kernelSize );
180   myUseROI = new QCheckBox( tr("USE_ROI") );
181   myUseROI->setChecked( true );
182
183   parametersLayout->addWidget( new QLabel( tr("KERNEL_SIZE") ), 0, 0 );
184   parametersLayout->addWidget( kernelSize, 0, 1 );
185   parametersLayout->addWidget( myUseROI, 0, 2 );
186
187   // Corners Parameters 
188   myCornersParameters = new QFrame();
189   myCornersParameters->setFrameStyle(QFrame::NoFrame);
190   QDoubleSpinBox* qualityLevel = new QDoubleSpinBox();
191   qualityLevel->setValue( 0.2 );
192   qualityLevel->setSingleStep( 0.1 );
193   qualityLevel->setRange( 0.01, 0.99 );
194   myWidgets.insert( QUALITY_LEVEL, qualityLevel );
195   QDoubleSpinBox* minDistance = new QDoubleSpinBox();
196   minDistance->setValue( 1 );
197   myWidgets.insert( MIN_DISTANCE, minDistance );
198   QComboBox* typeCriteria = new QComboBox();
199   typeCriteria->addItems( QStringList() << tr("CV_TERMCRIT_ITER") << tr("CV_TERMCRIT_EPS") << tr("CV_TERMCRIT_ITER | CV_TERMCRIT_EPS") );
200   typeCriteria->setCurrentIndex( 2 );
201   myWidgets.insert( TYPE_CRITERIA, typeCriteria );
202   QSpinBox* maxIter = new QSpinBox();
203   maxIter->setValue( 20 );
204   maxIter->setRange( 1, 100 );
205   myWidgets.insert( MAX_ITER, maxIter );
206   QDoubleSpinBox* epsilon = new QDoubleSpinBox();
207   epsilon->setValue( 0.03 );
208   epsilon->setSingleStep( 0.01 );
209   myWidgets.insert( EPSILON, epsilon );
210
211   QGridLayout* cornersLayout = new QGridLayout();
212   cornersLayout->setMargin( 0 );
213   cornersLayout->addWidget( new QLabel( tr("QUALITY_LEVEL") ), 0, 0 );
214   cornersLayout->addWidget( qualityLevel, 0, 1 );
215   cornersLayout->addWidget( new QLabel( tr("MIN_DISTANCE") ), 0, 2 );
216   cornersLayout->addWidget( minDistance, 0 ,3 );
217   cornersLayout->addWidget( new QLabel( tr("TYPE_CRITERIA") ), 1, 0 );
218   cornersLayout->addWidget( typeCriteria, 1, 1, 1, 3 );
219   cornersLayout->addWidget( new QLabel( tr("MAX_ITER") ), 2, 0 );
220   cornersLayout->addWidget( maxIter, 2, 1 );
221   cornersLayout->addWidget( new QLabel( tr("EPSILON") ), 2, 2 );
222   cornersLayout->addWidget( epsilon, 2 , 3 );
223
224   myCornersParameters->setLayout( cornersLayout );
225
226   // Contours Parameters
227   myContoursParameters = new QFrame();
228   myContoursParameters->setFrameStyle(QFrame::NoFrame);
229
230   QComboBox* findContoursMethod = new QComboBox();
231   findContoursMethod->addItems( QStringList() << tr("CV_CHAIN_APPROX_NONE") << tr("CV_CHAIN_APPROX_SIMPLE") << tr("CV_CHAIN_APPROX_TC89_L1") << tr("CV_CHAIN_APPROX_TC89_KCOS") );
232   myWidgets.insert( FIND_CONTOURS_METHOD, findContoursMethod );
233
234   myCannyParameters = new QFrame();
235   myCannyParameters->setFrameStyle(QFrame::NoFrame);
236   QSpinBox* threshold = new QSpinBox();
237   threshold->setRange( 0, 255 );
238   threshold->setValue( 100 );
239   myWidgets.insert( LOW_THRESHOLD, threshold );
240   QSpinBox* ratio = new QSpinBox();
241   ratio->setValue( 3 );
242   ratio->setRange( 0, 255 );
243   myWidgets.insert( RATIO, ratio );
244   QCheckBox* L2gradient = new QCheckBox(tr("L2GRADIENT"));
245   L2gradient->setChecked(true);
246   myWidgets.insert( L2GRADIENT, L2gradient );
247
248   QGridLayout* cannyLayout = new QGridLayout();
249   cannyLayout->setMargin( 0 );
250   cannyLayout->addWidget( new QLabel( tr("LOWTHRESHOLD") ), 0, 0 );
251   cannyLayout->addWidget( threshold, 0, 1 );
252   cannyLayout->addWidget( new QLabel( tr("RATIO") ), 0, 2 );
253   cannyLayout->addWidget( ratio, 0, 3 );
254   cannyLayout->addWidget( L2gradient, 1, 0 );
255
256   myCannyParameters->setLayout( cannyLayout );
257   myCannyParameters->setHidden( true );
258
259   myColorFilterParameters = new QFrame();
260   myColorFilterParameters->setFrameStyle(QFrame::NoFrame);
261
262   QSpinBox* smoothSize = new QSpinBox();
263   smoothSize->setValue( 3 );
264   smoothSize->setSingleStep( 2 );
265   smoothSize->setRange( 1, 1000 );
266   myWidgets.insert( SMOOTH_SIZE, smoothSize );
267   QSpinBox* hbins = new QSpinBox();
268   hbins->setValue( 30 );
269   hbins->setRange( 0, 179 );
270   myWidgets.insert( HBINS, hbins );
271   QSpinBox* sbins = new QSpinBox();
272   sbins->setValue( 32 );
273   sbins->setRange( 0, 255 );
274   myWidgets.insert( SBINS, sbins );
275   QComboBox* histType = new QComboBox();
276   histType->addItems( QStringList() << tr("CV_HIST_ARRAY") << tr("CV_HIST_SPARSE") );
277   myWidgets.insert( HIST_TYPE, histType );
278   QDoubleSpinBox* thresholdValue = new QDoubleSpinBox();
279   thresholdValue->setRange( 0, 254 );
280   // 1 is a good default value for the threshold. It means that we are very permissive
281   // about what will be considered INSIDE the zone we want to find the frontier of
282   // This makes the algorithm more robust against a bit inhomogeneous parts in the zone
283   // that we want to delimitate.
284   // The drawback is if we want to delimitate a zone wich color is very similar to the zone
285   // we consider as the OUTSIDE, the result will be bad.
286   // The current use cases are more of the first form : 
287   //  - Strongly contrasted INSIDE and OUTSIDE zones
288   //  - Small inhomogenities in each zone
289   thresholdValue->setValue( 1 );
290   myWidgets.insert( THRESHOLD_VALUE, thresholdValue );
291   QDoubleSpinBox* maxThreshold = new QDoubleSpinBox();
292   maxThreshold->setRange( 1, 255 );
293   maxThreshold->setValue( 255 );
294   myWidgets.insert( MAX_THRESHOLD, maxThreshold );
295
296   QGridLayout* colorFilterLayout = new QGridLayout();
297   colorFilterLayout->setMargin( 0 );
298   colorFilterLayout->addWidget( new QLabel( tr("SMOOTH_SIZE") ), 0, 0 );
299   colorFilterLayout->addWidget( smoothSize, 0, 1 );
300   colorFilterLayout->addWidget( new QLabel( tr("HBINS") ), 1, 0 );
301   colorFilterLayout->addWidget( hbins, 1, 1 );
302   colorFilterLayout->addWidget( new QLabel( tr("SBINS") ), 1, 2 );
303   colorFilterLayout->addWidget( sbins, 1, 3 );
304   colorFilterLayout->addWidget( new QLabel( tr("HIST_TYPE") ), 2, 0 );
305   colorFilterLayout->addWidget( histType, 2, 1, 1, 3 );
306   colorFilterLayout->addWidget( new QLabel( tr("THRESHOLD_VALUE") ), 3, 0 );
307   colorFilterLayout->addWidget( thresholdValue, 3, 1 );
308   colorFilterLayout->addWidget( new QLabel( tr("MAX_THRESHOLD") ), 3, 2 );
309   colorFilterLayout->addWidget( maxThreshold, 3, 3 );
310
311   myColorFilterParameters->setLayout( colorFilterLayout );
312   QGridLayout* contoursLayout = new QGridLayout();
313   contoursLayout->setMargin( 0 );
314   contoursLayout->addWidget( new QLabel( tr("FIND_CONTOURS_METHOD") ), 0, 0 );
315   contoursLayout->addWidget( findContoursMethod, 0, 1 );
316   contoursLayout->addWidget( myCannyParameters, 1, 0, 1, 3 );
317   contoursLayout->addWidget( myColorFilterParameters, 1, 0, 1, 3  );
318
319   myContoursParameters->setLayout( contoursLayout );
320
321   parametersLayout->addWidget( myCornersParameters, 1, 0, 1, 3 );
322   parametersLayout->addWidget( myContoursParameters, 1, 0, 1, 3 );
323
324   QVBoxLayout* layout = new QVBoxLayout(centralWidget());
325   layout->setMargin(0); layout->setSpacing(6);
326 //   layout->addWidget( myViewGroup);
327   layout->addLayout( parametersLayout );
328   layout->addWidget( mySelectionGroup);
329   layout->addWidget( myOutputGroup);
330   
331 //   mainFrame()->GroupBoxName->hide();
332   
333   // Build an instance of detection used to perform image processing operations
334   myDetector = new ShapeRec_FeatureDetector();
335   
336   setHelpFileName( "shape_recognition_page.html" );
337   
338   Init();
339   
340 }
341
342 //=================================================================================
343 // function : ~EntityGUI_FeatureDetectorDlg()
344 // purpose  : Destroys the object and frees any allocated resources
345 //=================================================================================
346 EntityGUI_FeatureDetectorDlg::~EntityGUI_FeatureDetectorDlg()
347 {
348   delete myDetector;
349 }
350
351 //=================================================================================
352 // function : Init()
353 // purpose  :
354 //=================================================================================
355 void EntityGUI_FeatureDetectorDlg::Init()
356 {
357   connect( myGeomGUI,         SIGNAL( SignalCloseAllDialogs() ), this, SLOT( ClickOnCancel() ) );
358   connect( buttonOk(),        SIGNAL( clicked() ),               this, SLOT( ClickOnOk() ) );
359   connect( buttonApply(),     SIGNAL( clicked() ),               this, SLOT( ClickOnApply() ) );
360   connect( myUseROI,          SIGNAL( toggled(bool) ),           this, SLOT( onCheckBoxClicked(bool) ) );
361   connect( this,              SIGNAL(constructorsClicked(int)),  this, SLOT(ConstructorsClicked(int))); 
362   connect( mySelectionGroup->PushButton2,      SIGNAL( clicked() ),               this, SLOT( onButtonClicked() ) );
363   connect( mySelectionGroup->PushButton1,       SIGNAL( clicked() ),               this, SLOT( onButtonClicked() ) );  
364 //   connect( myViewButtonGroup, SIGNAL( buttonClicked( int ) ),    this, SLOT( onViewClicked( int ) ) );
365   connect( myGeomGUI->getApp()->selectionMgr(), SIGNAL( currentSelectionChanged() ),this, SLOT( SelectionIntoArgument() ) );
366   
367   myConstructorId = 0;
368   mySelectionGroup->PushButton1->click();
369   
370 //   SetEditCurrentArgument();
371   SelectionIntoArgument();
372   
373   initName(tr("GEOM_CONTOURS")); 
374   resize(100,100);
375   
376 //   myViewGroup->RadioButton1->setChecked(true);
377   myOutputGroup->RadioButton1->setChecked(true);
378   
379   gp_Pnt aOrigin = gp_Pnt(0, 0, 0);
380   gp_Dir aDirZ = gp_Dir(0, 0, 1);
381   gp_Dir aDirX = gp_Dir(1, 0, 0);
382   
383   aGlobalCS = gp_Ax3(aOrigin, aDirZ, aDirX);
384   
385   myStartPnt = gp_Pnt(0,0,0);
386   myEndPnt = myStartPnt;
387   
388   myGeomGUI->SetWorkingPlane( aGlobalCS );
389   myGeomGUI->ActiveWorkingPlane();
390   
391   ConstructorsClicked(myConstructorId);
392 }
393
394 //=================================================================================
395 // function : SelectionIntoArgument()
396 // purpose  : Called when selection as changed or other case
397 //=================================================================================
398 void EntityGUI_FeatureDetectorDlg::SelectionIntoArgument()
399 {
400   
401   // TODO supprimer les lignes qui ne servent à rien le cas échéant
402   SUIT_ViewWindow*       theViewWindow  = getDesktop()->activeWindow();
403   std::map< std::string , std::vector<Handle(AIS_InteractiveObject)> >::iterator AISit;
404   SOCC_Viewer* soccViewer = (SOCC_Viewer*)(theViewWindow->getViewManager()->getViewModel());
405
406   if (!myEditCurrentArgument->isEnabled())
407     return;
408   
409   myEditCurrentArgument->setText( "" );
410
411   LightApp_SelectionMgr* aSelMgr = myGeomGUI->getApp()->selectionMgr();
412   SALOME_ListIO aSelList;
413   aSelMgr->selectedObjects(aSelList);
414   SALOME_ListIteratorOfListIO anIt( aSelList );
415   
416   for( ; anIt.More(); anIt.Next() )
417     if( !anIt.Value().IsNull() )
418     {
419       myFaceEntry = anIt.Value()->getEntry();
420     }
421
422   if (aSelList.Extent() != 1) {
423     if (myEditCurrentArgument == mySelectionGroup->LineEdit1) 
424       myFace.nullify();
425     return;
426   }
427
428   TopAbs_ShapeEnum aNeedType = TopAbs_FACE ;
429   GEOM::GeomObjPtr aSelectedObject = getSelected( aNeedType );
430   TopoDS_Shape aShape;
431   if ( aSelectedObject && GEOMBase::GetShape( aSelectedObject.get(), aShape ) && !aShape.IsNull() ) {
432     QString aName = GEOMBase::GetName( aSelectedObject.get() );
433     myEditCurrentArgument->setText( aName );
434     
435     if ( myEditCurrentArgument == mySelectionGroup->LineEdit1 ) {
436       myFace = aSelectedObject;
437       AISit = soccViewer->entry2aisobjects.find(myFaceEntry.toStdString());
438       if (AISit == soccViewer->entry2aisobjects.end())
439         return;
440       
441       Handle(AIS_InteractiveObject) myAIS = (*AISit).second[0];
442       Handle(GEOM_AISShape) myAISShape;
443       if( myAIS->IsInstance( STANDARD_TYPE(GEOM_AISShape) ) ) {
444         myAISShape = Handle(GEOM_AISShape)::DownCast( myAIS );
445       }
446       else
447         return ;
448
449       SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( SUIT_Session::session()->activeApplication()->activeStudy() );
450       if ( !study ) return;
451       LightApp_Application* app = ::qobject_cast<LightApp_Application*>( study->application() );
452       if ( !app ) return;
453       SUIT_ViewManager* vm = app->activeViewManager();
454       if ( !vm ) return;
455       PropMap propMap = study->getObjectProperties( vm->getGlobalId(), myFaceEntry );
456       QString theImgFileName = propMap.value( GEOM::propertyName( GEOM::Texture ) ).toString();
457       if ( theImgFileName.isEmpty() )
458         return ;
459
460       // Setting the image caracteristics
461       myDetector->SetPath( theImgFileName.toStdString() );
462       height            =  myDetector->GetImgHeight();
463       width             =  myDetector->GetImgWidth();
464       pictureLeft       = -0.5 * width;              // X coordinate of the top left  corner of the background image in the view
465       pictureTop        =  0.5 * height;             // Y coordinate of both top corners
466       
467     } 
468   }
469   
470 }
471
472 //=================================================================================
473 // function : acceptMouseEvent()
474 // purpose  :
475 //=================================================================================
476 bool EntityGUI_FeatureDetectorDlg::acceptMouseEvent() const
477
478   return mySelectionGroup->PushButton2->isChecked();  
479 }
480
481 //=======================================================================
482 // function : ClickOnOk()
483 // purpose  :
484 //=======================================================================
485 void EntityGUI_FeatureDetectorDlg::ClickOnOk()
486 {
487   setIsApplyAndClose( true );
488   if (onAccept())
489     ClickOnCancel();
490 }
491
492 //=================================================================================
493 // function : ClickOnApply()
494 // purpose  :
495 //=================================================================================
496 bool EntityGUI_FeatureDetectorDlg::ClickOnApply()
497 {
498   if (!onAccept())
499     return false;
500
501 //   initName();
502   ConstructorsClicked(getConstructorId());
503   return true;
504 }
505
506 //=================================================================================
507 // function : onConstructorClicked(int)
508 // purpose  :
509 //=================================================================================
510 void EntityGUI_FeatureDetectorDlg::ConstructorsClicked(int id)
511 {
512   MESSAGE("Constructor id ="<<id)
513   myConstructorId = id;
514   switch (id)
515   {
516     case CORNERS:
517       myCornersParameters->show();
518       myContoursParameters->hide();
519 //       myViewGroup->show();
520 //       mySelectionGroup->show();
521       myOutputGroup->hide();
522 //       mySelectionGroup->TextLabel2->setText(tr("GEOM_DETECT_ZONE"));
523       initName(tr("GEOM_CORNERS"));
524       break;
525     case CONTOURS:
526       myCornersParameters->hide();
527       myContoursParameters->show();
528 //       myViewGroup->hide();
529 //       mySelectionGroup->hide();
530 //       mySelectionGroup->show();
531       myOutputGroup->show();
532       mySelectionGroup->TextLabel2->setText(tr("GEOM_COLOR_FILTER"));
533       initName(tr("GEOM_CONTOURS"));
534       break;
535     case LINES:
536 //       myViewGroup->hide();
537 //       mySelectionGroup->hide();
538 //       mySelectionGroup->show();
539       myOutputGroup->hide();
540       mySelectionGroup->TextLabel2->setText(tr(""));
541       initName(tr("GEOM_LINES"));
542       break;
543   }
544 }
545
546 // //=================================================================================
547 // // function : onViewClicked()
548 // // purpose  :
549 // //=================================================================================
550 // void EntityGUI_FeatureDetectorDlg::onViewClicked(int id)
551 // {
552 //   gp_Pnt aOrigin = gp_Pnt(0, 0, 0);
553 //   gp_Dir aDirZ;
554 //   gp_Dir aDirX;
555 //   
556 //   switch(id)
557 //   {
558 //     case XY:
559 //         aDirZ = gp_Dir(0, 0, 1);
560 //         aDirX = gp_Dir(1, 0, 0);
561 //       break;
562 //     case YZ:
563 //         aDirZ = gp_Dir(1, 0, 0);
564 //         aDirX = gp_Dir(0, 1, 0);
565 //       break;
566 //     case XZ:
567 //         aDirZ = gp_Dir(0, -1, 0);
568 //         aDirX = gp_Dir(1, 0 , 0);
569 //       break;
570 //   }
571 //   
572 //   myWPlane = gp_Ax3(aOrigin, aDirZ, aDirX);
573 //   myGeomGUI->SetWorkingPlane( myWPlane );
574 //   myGeomGUI->ActiveWorkingPlane();
575 //   
576 // }
577
578 //=================================================================================
579 // function : onButtonClicked()
580 // purpose  :
581 //=================================================================================
582 void EntityGUI_FeatureDetectorDlg::onButtonClicked()
583 {
584   QPushButton* send = (QPushButton*)sender();
585   if (send == mySelectionGroup->PushButton2)
586   {
587     mySelectionGroup->LineEdit1->setEnabled(false);
588   }
589   else if (send == mySelectionGroup->PushButton1)
590   {
591     myStartPnt = gp_Pnt(0,0,0);
592     myEndPnt   = myStartPnt;
593     myEditCurrentArgument = mySelectionGroup->LineEdit1;
594     mySelectionGroup->LineEdit1->setEnabled(true);   
595   }
596 }
597
598 //=================================================================================
599 // function : onCheckBoxClicked(bool)
600 // purpose  :
601 //=================================================================================
602 void EntityGUI_FeatureDetectorDlg::onCheckBoxClicked( bool isChecked )
603 {
604   mySelectionGroup->TextLabel2->setVisible( isChecked );
605   mySelectionGroup->Frame->setVisible( isChecked );
606   mySelectionGroup->PushButton2->setVisible( isChecked );
607   myCannyParameters->setHidden( isChecked );
608   myColorFilterParameters->setHidden( !isChecked );
609 }
610
611 //=================================================================================
612 // function : parametersChanged()
613 // purpose  :
614 //=================================================================================
615 ShapeRec_Parameters* EntityGUI_FeatureDetectorDlg::parametersChanged()
616 {
617   ShapeRec_Parameters* aParameters = new ShapeRec_Parameters();
618
619   if ( myConstructorId == CORNERS ) {
620     ShapeRec_CornersParameters* aCornersParameters = dynamic_cast<ShapeRec_CornersParameters*>( aParameters );
621     if ( !aCornersParameters ) aCornersParameters = new ShapeRec_CornersParameters();
622     aCornersParameters->qualityLevel = (dynamic_cast<QDoubleSpinBox*>(myWidgets[QUALITY_LEVEL]))->value();
623     aCornersParameters->minDistance  = (dynamic_cast<QDoubleSpinBox*>(myWidgets[MIN_DISTANCE]))->value();
624     switch ( (dynamic_cast<QComboBox*>(myWidgets[TYPE_CRITERIA]))->currentIndex() ) {
625     case 0: aCornersParameters->typeCriteria = CV_TERMCRIT_ITER;
626     case 1: aCornersParameters->typeCriteria = CV_TERMCRIT_EPS;
627     case 2: aCornersParameters->typeCriteria = CV_TERMCRIT_ITER | CV_TERMCRIT_EPS;
628     }
629     aCornersParameters->maxIter = (dynamic_cast<QSpinBox*>(myWidgets[MAX_ITER]))->value();
630     aCornersParameters->epsilon = (dynamic_cast<QDoubleSpinBox*>(myWidgets[EPSILON]))->value();
631     aParameters = aCornersParameters;
632   }
633   else if ( myConstructorId == CONTOURS ) {
634     if ( !myUseROI->isChecked() ) { 
635       ShapeRec_CannyParameters* aCannyParameters = dynamic_cast<ShapeRec_CannyParameters*>( aParameters );
636       if ( !aCannyParameters ) aCannyParameters = new ShapeRec_CannyParameters();
637       aCannyParameters->lowThreshold = (dynamic_cast<QSpinBox*>(myWidgets[LOW_THRESHOLD]))->value();
638       aCannyParameters->ratio        = (dynamic_cast<QSpinBox*>(myWidgets[RATIO]))->value();
639       aCannyParameters->L2gradient   = (dynamic_cast<QCheckBox*>(myWidgets[L2GRADIENT]))->isChecked();
640       aParameters = aCannyParameters;
641     }
642     else {
643       ShapeRec_ColorFilterParameters* aColorFilterParameters = dynamic_cast<ShapeRec_ColorFilterParameters*>( aParameters );
644       if ( !aColorFilterParameters ) aColorFilterParameters = new ShapeRec_ColorFilterParameters();
645       int aSmoothSize = (dynamic_cast<QSpinBox*>(myWidgets[SMOOTH_SIZE]))->value();
646       aColorFilterParameters->smoothSize  = aSmoothSize % 2 == 0 ? aSmoothSize - 1 : aSmoothSize;
647       aColorFilterParameters->histSize[0] = (dynamic_cast<QSpinBox*>(myWidgets[HBINS]))->value();
648       aColorFilterParameters->histSize[1] = (dynamic_cast<QSpinBox*>(myWidgets[SBINS]))->value();
649       switch ( (dynamic_cast<QComboBox*>(myWidgets[HIST_TYPE]))->currentIndex() ) {
650       case 0: aColorFilterParameters->histType = CV_HIST_ARRAY;  break;
651       case 1: aColorFilterParameters->histType = CV_HIST_SPARSE; break;
652       }
653       aColorFilterParameters->threshold    = (dynamic_cast<QDoubleSpinBox*>(myWidgets[THRESHOLD_VALUE]))->value();
654       aColorFilterParameters->maxThreshold = (dynamic_cast<QDoubleSpinBox*>(myWidgets[MAX_THRESHOLD]))->value();
655       aParameters = aColorFilterParameters;
656     }
657   }
658  
659   aParameters->kernelSize = ( (dynamic_cast<QComboBox*>(myWidgets[KERNEL_SIZE]))->currentText() ).toInt();
660   switch ( (dynamic_cast<QComboBox*>(myWidgets[FIND_CONTOURS_METHOD]))->currentIndex() ) {
661   case 0: aParameters->findContoursMethod = CV_CHAIN_APPROX_NONE;      break;
662   case 1: aParameters->findContoursMethod = CV_CHAIN_APPROX_SIMPLE;    break;
663   case 2: aParameters->findContoursMethod = CV_CHAIN_APPROX_TC89_L1;   break;
664   case 3: aParameters->findContoursMethod = CV_CHAIN_APPROX_TC89_KCOS; break;
665   }
666
667   return aParameters;
668 }
669
670 //=================================================================================
671 // function : setStartPnt( const QPoint& )
672 // purpose  :
673 //=================================================================================
674 void EntityGUI_FeatureDetectorDlg::setStartPnt(const gp_Pnt& theStartPnt)
675 {
676   myStartPnt = theStartPnt;
677   MESSAGE("myStartPnt = ("<<theStartPnt.X()<<", "<<theStartPnt.Y()<<")")
678 }
679
680 //=================================================================================
681 // function : setEndPnt( const QPoint& )
682 // purpose  :
683 //=================================================================================
684 void EntityGUI_FeatureDetectorDlg::setEndPnt(const gp_Pnt& theEndPnt)
685 {
686   myEndPnt = theEndPnt;
687   MESSAGE("myEndPnt = ("<<theEndPnt.X()<<", "<<theEndPnt.Y()<<")")
688   if (setSelectionRect() && myDetector->GetImgHeight() > 0)
689     showImageSample();
690 }
691
692 //=================================================================================
693 // function : setSelectionRect()
694 // purpose  :
695 //=================================================================================
696 bool EntityGUI_FeatureDetectorDlg::setSelectionRect()
697
698   // Set detection rectangle in the background image coordinates system
699   double left    = std::min( myStartPnt.X(), myEndPnt.X() );
700   double top     = std::max( myStartPnt.Y(), myEndPnt.Y() );
701   double right   = std::max( myStartPnt.X(), myEndPnt.X() );
702   double bottom  = std::min( myStartPnt.Y(), myEndPnt.Y() );
703   
704   QPoint topLeft     = QPoint(left  - pictureLeft, pictureTop - top   );
705   QPoint bottomRight = QPoint(right - pictureLeft, pictureTop - bottom);
706   
707   myRect = QRect(topLeft, bottomRight);
708   
709   return (!myRect.isEmpty() && myRect.width() > 1);
710 }
711
712 //=================================================================================
713 // function : showImageSample()
714 // purpose  : Display a preview of the image sample selected by the user
715 //=================================================================================
716 void EntityGUI_FeatureDetectorDlg::showImageSample()
717
718   // Cropp the image to the selection rectangle given by the user
719   myDetector->SetROI( myRect ); 
720   std::string samplePicturePath = myDetector->CroppImage();
721   
722   // Display the result
723   QPixmap pixmap(QString(samplePicturePath.c_str()));
724   mySelectionGroup->FrameLabel->setPixmap(pixmap);
725   mySelectionGroup->FrameLabel->setMask(pixmap.mask());
726 }
727
728 //=================================================================================
729 // function : createOperation
730 // purpose  :
731 //=================================================================================
732 GEOM::GEOM_IOperations_ptr EntityGUI_FeatureDetectorDlg::createOperation()
733 {
734   return myGeomGUI->GetGeomGen()->GetIShapesOperations( getStudyId() );
735 }
736
737 //=================================================================================
738 // function : execute()
739 // purpose  :
740 //=================================================================================
741 bool EntityGUI_FeatureDetectorDlg::execute( ObjectList& objects )
742 {
743   bool res = false;
744   
745   GEOM::GEOM_IBasicOperations_var  aBasicOperations  = myGeomGUI->GetGeomGen()->GetIBasicOperations( getStudyId() );
746   GEOM::GEOM_IShapesOperations_var aShapesOperations = GEOM::GEOM_IShapesOperations::_narrow( getOperation() );
747
748   ShapeRec_Parameters* parameters = parametersChanged();
749   if ( !parameters ) parameters = new ShapeRec_Parameters();
750
751   bool useROI = myUseROI->isChecked() && !myRect.isEmpty();
752   try {
753     if (myConstructorId == CORNERS)
754     {
755       double subPictureLeft;
756       double subPictureTop;
757       if( useROI )
758       {
759         subPictureLeft    = myStartPnt.X();                
760         subPictureTop     = myStartPnt.Y();
761       }
762       else
763       {
764         subPictureLeft    = pictureLeft;
765         subPictureTop     = pictureTop;
766       }
767       myDetector->ComputeCorners( useROI, parameters );
768       CvPoint2D32f* corners     = myDetector->GetCorners();
769       int cornerCount           = myDetector->GetCornerCount();
770       int i;
771     
772       // Build the geom objects associated to the detected corners and returned by execute   
773       if( !aBasicOperations->_is_nil() && !aShapesOperations->_is_nil() ) 
774       {
775         GEOM::GEOM_Object_var  aGeomCorner;
776         GEOM::ListOfGO_var     geomCorners = new GEOM::ListOfGO();
777         geomCorners->length( cornerCount );
778         for (i = 0; i < cornerCount; i++)
779         {
780           double x = subPictureLeft + corners[i].x;
781           double y = subPictureTop  - corners[i].y;
782           double z =  0;
783         
784           aGeomCorner = aBasicOperations->MakePointXYZ( x,y,z );
785         
786           geomCorners[i] = aGeomCorner;  
787         } 
788         GEOM::GEOM_Object_var aCompound = aShapesOperations->MakeCompound(geomCorners);    
789         if ( !aCompound->_is_nil() )
790         {
791           // Dark blue color
792           SALOMEDS::Color aColor;
793           aColor.R = 0;
794           aColor.G = 0;
795           aColor.B = 0.8;
796
797           aCompound->SetColor(aColor);
798           aCompound->SetMarkerStd(GEOM::MT_POINT,GEOM::MS_30);
799           objects.push_back( aCompound._retn() );
800           res = true;
801         }
802       }   
803     }
804     else if (myConstructorId == CONTOURS)
805     {    
806       GEOM::GEOM_ICurvesOperations_var aCurveOperations = myGeomGUI->GetGeomGen()->GetICurvesOperations( getStudyId() );
807
808       myDetector->ComputeContours( useROI, parameters );
809       std::vector< std::vector<cv::Point> >   contours  = myDetector->GetContours();
810       std::vector<cv::Vec4i>                  hierarchy = myDetector->GetContoursHierarchy();
811     
812       std::vector< cv::Point >                contour;
813       int idx = 0;
814       
815       GEOM::ListOfGO_var                      geomContours = new GEOM::ListOfGO();
816       int contourCount = 0;
817     
818       bool insert;
819     
820       MESSAGE("hierarchy.size() =" << hierarchy.size()) 
821       if ( hierarchy.size() < 1 ) {
822         getOperation()->SetErrorCode( "Impossible detected contours" );
823         return false;
824       }
825
826       for( ; idx >= 0; idx = hierarchy[idx][0])
827       {
828 //       for(int count=0, child=idx; child>=0, count<1; child=hierarchy[idx][2], count++)
829 //       {     
830 //         contour = contours[child];
831         contour = contours[idx];
832         std::vector< cv::Point >::iterator it;
833         std::vector< cv::Point >::iterator it_previous;
834         std::vector< cv::Point >::iterator it_next;
835         GEOM::GEOM_Object_var  aGeomContourPnt;
836         GEOM::ListOfGO_var     geomContourPnts = new GEOM::ListOfGO();
837        
838         geomContourPnts->length( contour.size() );
839
840         int j = 0;
841         std::set< std::vector<int> > existing_points;
842         std::pair< std::set< std::vector<int> >::iterator,bool > pnt_it;
843         for ( it=contour.begin() ; it < contour.end()-1; it++ )
844         {
845           int pnt_array[] = {it->x,it->y};     
846           std::vector<int> pnt (pnt_array, pnt_array + sizeof(pnt_array) / sizeof(int) );
847
848           pnt_it=existing_points.insert(pnt);
849           if (pnt_it.second == true)         // To avoid double points in the contours
850           {
851             insert = true;
852             if (it!=contour.begin())         // From the second point on perform some checking to avoid loops in the contours we build
853             {
854               it_previous = boost::prior(it);
855               it_next = boost::next(it);
856               
857               double u_v_scalar_product = (it->x - it_previous->x) * (it_next->x - it->x) + 
858                                           (it->y - it_previous->y) * (it_next->y - it->y);                                       
859               if (u_v_scalar_product < 0)
860               {
861                 double u_v_det = (it->x - it_previous->x) * (it_next->y - it->y) - 
862                                  (it->y - it_previous->y) * (it_next->x - it->x);
863                                           
864                 double norme_u = sqrt ( double(it->x - it_previous->x) * double(it->x - it_previous->x) +
865                                         double(it->y - it_previous->y) * double(it->y - it_previous->y) );
866                 
867                 double norme_v = sqrt ( double(it->x - it_next->x) * double(it->x - it_next->x) +
868                                         double(it->y - it_next->y) * double(it->y - it_next->y) );
869                                                                                                 
870                 double u_v_sinus = u_v_det / (norme_u * norme_v);
871                 
872                 if (fabs(u_v_sinus) < Precision::Confusion())
873                 { 
874                   insert = false;
875                 }                         
876               }
877             }
878             double x = -0.5 *width  + it->x;
879             double y =  0.5 *height - it->y;
880             double z =  0;
881             if (insert)
882             {
883               aGeomContourPnt    = aBasicOperations->MakePointXYZ( x,y,z );
884               geomContourPnts->length( j+1 );
885               geomContourPnts[j] = aGeomContourPnt;
886               j++;
887             }
888           }
889         }
890         
891         GEOM::GEOM_Object_var aWire;
892         if(myOutputGroup->RadioButton2->isChecked())
893         {
894           aWire = aCurveOperations->MakePolyline(geomContourPnts.in(), false);
895         }
896         else if(myOutputGroup->RadioButton1->isChecked())
897         {
898           aWire = aCurveOperations->MakeSplineInterpolation(geomContourPnts.in(), /*closed =*/ false, /*reordering =*/ false);
899         }
900         else
901           return res;
902         
903         if ( !aWire->_is_nil() )
904         {
905           geomContours->length(contourCount + 1);
906           geomContours[contourCount] = aWire;
907           contourCount++;
908         }
909 //       }
910       }
911       GEOM::GEOM_Object_var aContoursCompound = aShapesOperations->MakeCompound(geomContours);
912       if ( !aContoursCompound->_is_nil() )
913       {
914         objects.push_back( aContoursCompound._retn() );
915       }
916       res=true;
917     }
918   }
919   catch( ... ) {
920     getOperation()->SetErrorCode( "Impossible detected contours/corners" );
921     return false;
922   }
923   
924   // TEST not very conclusive
925   
926 //   else if(myConstructorId ==LINES)
927 //   {
928 //     myDetector->ComputeLines();
929 //     std::vector<cv::Vec4i>  lines = myDetector->GetLines();
930 //     GEOM::GEOM_Object_var  Pnt1;
931 //     GEOM::GEOM_Object_var  Pnt2;
932 //     GEOM::GEOM_Object_var  aLine;
933 //     
934 //     GEOM::ListOfGO_var     geomLines = new GEOM::ListOfGO();
935 //     int linesCount=0;
936 //     for( int i = 0; i < lines.size(); i++ )
937 //     {
938 //       Pnt1 = aBasicOperations->MakePointXYZ( -0.5 *width + lines[i][0], 0.5 *height - lines[i][1], 0 );
939 //       Pnt2 = aBasicOperations->MakePointXYZ( -0.5 *width + lines[i][2], 0.5 *height - lines[i][3], 0 );
940 //       aLine = aBasicOperations->MakeLineTwoPnt( Pnt1, Pnt2 );
941 //       if ( !aLine->_is_nil() )
942 //       {
943 //         geomLines->length(linesCount + 1);
944 //         geomLines[linesCount] = aLine;
945 //         linesCount++;
946 //       }
947 //     }
948 //     GEOM::GEOM_Object_var aLinesCompound = aShapesOperations->MakeCompound(geomLines);
949 //     if ( !aLinesCompound->_is_nil() )
950 //     {
951 //       objects.push_back( aLinesCompound._retn() );
952 //     }
953 // 
954 //     res=true;
955 //   }
956   
957   return res;
958 }
959
960 //=================================================================================
961 // function : getSourceObjects
962 // purpose  : virtual method to get source objects
963 //=================================================================================
964 QList<GEOM::GeomObjPtr> EntityGUI_FeatureDetectorDlg::getSourceObjects()
965 {
966   QList<GEOM::GeomObjPtr> res;
967   res << myFace;
968   return res;
969 }