Salome HOME
11213fd3898dab5d2ef9af9049d13ab652c42ed8
[modules/gui.git] / src / OCCViewer / OCCViewer_ClippingDlg.cxx
1 //  Copyright (C) 2007-2008  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.
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 #include "OCCViewer_ClippingDlg.h"
23
24 #include <QtxDoubleSpinBox.h>
25 #include <QtxAction.h>
26
27 #include "SUIT_Session.h"
28 #include "SUIT_ViewWindow.h"
29 #include "SUIT_ViewManager.h"
30 #include "OCCViewer_ViewWindow.h"
31 #include "OCCViewer_ViewPort3d.h"
32 #include "OCCViewer_ViewModel.h"
33
34 #include <V3d_View.hxx>
35 #include <Geom_Plane.hxx>
36 #include <Prs3d_Presentation.hxx>
37 #include <AIS_ListIteratorOfListOfInteractive.hxx>
38 #include <AIS_ListOfInteractive.hxx>
39 #include <AIS_InteractiveObject.hxx>
40 #include <AIS_InteractiveContext.hxx>
41 #include <IntAna_IntConicQuad.hxx>
42 #include <gp_Lin.hxx>
43 #include <gp_Pln.hxx>
44
45 // QT Includes
46 #include <QApplication>
47 #include <QGroupBox>
48 #include <QHBoxLayout>
49 #include <QVBoxLayout>
50 #include <QGridLayout>
51 #include <QLabel>
52 #include <QPushButton>
53 #include <QComboBox>
54 #include <QCheckBox>
55
56 /*!
57   Constructor
58   \param view - view window
59   \param parent - parent widget
60   \param name - dialog name
61   \param modal - is this dialog modal
62   \param fl - flags
63 */
64 OCCViewer_ClippingDlg::OCCViewer_ClippingDlg( OCCViewer_ViewWindow* view, QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl )
65 : QDialog( parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint ),
66   myView( view )
67 {
68   setObjectName( "OCCViewer_ClippingDlg" );
69   setModal( modal );
70
71   setWindowTitle( tr( "Clipping" ) );
72   
73   QVBoxLayout* topLayout = new QVBoxLayout( this );
74   topLayout->setMargin( 11 ); topLayout->setSpacing( 6 );
75   
76   /***************************************************************/
77   GroupPoint = new QGroupBox( this );
78   GroupPoint->setObjectName( "GroupPoint" );
79   GroupPoint->setTitle( tr("Base point") );
80   QGridLayout* GroupPointLayout = new QGridLayout( GroupPoint );
81   GroupPointLayout->setAlignment( Qt::AlignTop );
82   GroupPointLayout->setSpacing( 6 );
83   GroupPointLayout->setMargin( 11 );
84   
85   // Controls
86   const double min = -1e+7;
87   const double max =  1e+7;
88   const double step = 5;
89   const int precision = 3;
90
91   TextLabelX = new QLabel( GroupPoint );
92   TextLabelX->setObjectName( "TextLabelX" );
93   TextLabelX->setText( tr("X:") );
94   GroupPointLayout->addWidget( TextLabelX, 0, 0 );
95   
96   SpinBox_X = new QtxDoubleSpinBox( min, max, step, GroupPoint );
97   SpinBox_X->setObjectName("SpinBox_X" );
98   SpinBox_X->setDecimals( precision );
99   GroupPointLayout->addWidget( SpinBox_X, 0, 1 );
100
101   TextLabelY = new QLabel( GroupPoint );
102   TextLabelY->setObjectName( "TextLabelY" );
103   TextLabelY->setText( tr("Y:") );
104   GroupPointLayout->addWidget( TextLabelY, 0, 2 );
105
106   SpinBox_Y = new QtxDoubleSpinBox( min, max, step, GroupPoint );
107   SpinBox_Y->setObjectName("SpinBox_Y" );
108   SpinBox_Y->setDecimals( precision );
109   GroupPointLayout->addWidget( SpinBox_Y, 0, 3 );
110
111   TextLabelZ = new QLabel( GroupPoint );
112   TextLabelZ->setObjectName( "TextLabelZ" );
113   TextLabelZ->setText( tr("Z:") );
114   GroupPointLayout->addWidget( TextLabelZ, 0, 4 );
115
116   SpinBox_Z = new QtxDoubleSpinBox( min, max, step, GroupPoint );
117   SpinBox_Z->setObjectName("SpinBox_Z" );
118   SpinBox_Z->setDecimals( precision );
119   GroupPointLayout->addWidget( SpinBox_Z, 0, 5 );
120
121   resetButton  = new QPushButton( GroupPoint );
122   resetButton->setObjectName( "resetButton" );
123   resetButton->setText( tr( "Reset"  ) );
124   GroupPointLayout->addWidget( resetButton, 0, 6 );
125
126   /***************************************************************/
127   GroupDirection = new QGroupBox( this );
128   GroupDirection->setObjectName( "GroupDirection" );
129   GroupDirection->setTitle( tr("Direction") );
130   QGridLayout* GroupDirectionLayout = new QGridLayout( GroupDirection );
131   GroupDirectionLayout->setAlignment( Qt::AlignTop );
132   GroupDirectionLayout->setSpacing( 6 );
133   GroupDirectionLayout->setMargin( 11 );
134   
135   // Controls
136   TextLabelDx = new QLabel( GroupDirection );
137   TextLabelDx->setObjectName( "TextLabelDx" );
138   TextLabelDx->setText( tr("Dx:") );
139   GroupDirectionLayout->addWidget( TextLabelDx, 0, 0 );
140   
141   SpinBox_Dx = new QtxDoubleSpinBox( min, max, step, GroupDirection );
142   SpinBox_Dx->setObjectName("SpinBox_Dx" );
143   SpinBox_Dx->setDecimals( precision );
144   GroupDirectionLayout->addWidget( SpinBox_Dx, 0, 1 );
145
146   TextLabelDy = new QLabel( GroupDirection );
147   TextLabelDy->setObjectName( "TextLabelDy" );
148   TextLabelDy->setText( tr("Dy:") );
149   GroupDirectionLayout->addWidget( TextLabelDy, 0, 2 );
150   
151   SpinBox_Dy = new QtxDoubleSpinBox( min, max, step, GroupDirection );
152   SpinBox_Dy->setObjectName("SpinBox_Dy" );
153   SpinBox_Dy->setDecimals( precision );
154   GroupDirectionLayout->addWidget( SpinBox_Dy, 0, 3 );
155
156   TextLabelDz = new QLabel( GroupDirection );
157   TextLabelDz->setObjectName( "TextLabelDz" );
158   TextLabelDz->setText( tr("Dz:") );
159   GroupDirectionLayout->addWidget( TextLabelDz, 0, 4 );
160   
161   SpinBox_Dz = new QtxDoubleSpinBox( min, max, step, GroupDirection );
162   SpinBox_Dz->setObjectName("SpinBox_Dz" );
163   SpinBox_Dz->setDecimals( precision );
164   GroupDirectionLayout->addWidget( SpinBox_Dz, 0, 5 );
165
166   invertButton  = new QPushButton( GroupDirection );
167   invertButton->setObjectName( "invertButton" );
168   invertButton->setText( tr( "Invert"  ) );
169   GroupDirectionLayout->addWidget( invertButton, 0, 6 );
170  
171   DirectionCB = new QComboBox( GroupDirection );
172   DirectionCB->setObjectName( "DirectionCB" );
173   DirectionCB->insertItem(DirectionCB->count(),tr("CUSTOM"));
174   DirectionCB->insertItem(DirectionCB->count(),tr("||X-Y"));
175   DirectionCB->insertItem(DirectionCB->count(),tr("||Y-Z"));
176   DirectionCB->insertItem(DirectionCB->count(),tr("||Z-X"));
177   GroupDirectionLayout->addWidget( DirectionCB, 1, 0, 1, 6 );
178   
179   /***************************************************************/
180   
181   PreviewChB = new QCheckBox( tr("Preview") ,this );
182   PreviewChB->setObjectName( "PreviewChB" );
183   PreviewChB->setChecked( true );
184   
185   /***************************************************************/
186   QGroupBox* GroupButtons = new QGroupBox( this );
187   GroupButtons->setObjectName( "GroupButtons" );
188   QHBoxLayout* GroupButtonsLayout = new QHBoxLayout( GroupButtons );
189   GroupButtonsLayout->setAlignment( Qt::AlignTop );
190   GroupButtonsLayout->setMargin( 11 ); GroupButtonsLayout->setSpacing( 6 );
191   
192   buttonApply = new QPushButton( GroupButtons );
193   buttonApply->setObjectName( "buttonApply" );
194   buttonApply->setText( tr( "BUT_APPLY"  ) );
195   buttonApply->setAutoDefault( TRUE ); 
196   buttonApply->setDefault( TRUE );
197   GroupButtonsLayout->addWidget( buttonApply );
198   
199   GroupButtonsLayout->addStretch();
200   
201   buttonClose = new QPushButton( GroupButtons );
202   buttonClose->setObjectName( "buttonClose" );
203   buttonClose->setText( tr( "BUT_CLOSE"  ) );
204   buttonClose->setAutoDefault( TRUE );
205   GroupButtonsLayout->addWidget( buttonClose );
206
207   /***************************************************************/
208   
209   topLayout->addWidget( GroupPoint );
210   topLayout->addWidget( GroupDirection );
211   
212   topLayout->addWidget( PreviewChB );
213
214   topLayout->addWidget( GroupButtons );
215
216   /* initializations */
217
218   SpinBox_X->setValue( 0.0 );
219   SpinBox_Y->setValue( 0.0 );
220   SpinBox_Z->setValue( 0.0 );
221
222   SpinBox_Dx->setValue( 1.0 );
223   SpinBox_Dy->setValue( 1.0 );
224   SpinBox_Dz->setValue( 1.0 );
225
226   /* signals and slots connections */
227   connect( resetButton,  SIGNAL (clicked() ), this, SLOT( onReset() ) );
228   connect( invertButton, SIGNAL (clicked() ), this, SLOT( onInvert() ) ) ;
229
230   connect( SpinBox_X,  SIGNAL ( valueChanged( double ) ),  this, SLOT( onValueChanged() ) );
231   connect( SpinBox_Y,  SIGNAL ( valueChanged( double ) ),  this, SLOT( onValueChanged() ) );
232   connect( SpinBox_Z,  SIGNAL ( valueChanged( double ) ),  this, SLOT( onValueChanged() ) );
233   connect( SpinBox_Dx, SIGNAL ( valueChanged( double ) ),  this, SLOT( onValueChanged() ) );
234   connect( SpinBox_Dy, SIGNAL ( valueChanged( double ) ),  this, SLOT( onValueChanged() ) );
235   connect( SpinBox_Dz, SIGNAL ( valueChanged( double ) ),  this, SLOT( onValueChanged() ) );
236    
237   connect( DirectionCB, SIGNAL ( activated ( int ) ), this, SLOT( onModeChanged( int ) ) ) ;
238
239   connect( PreviewChB, SIGNAL ( toggled ( bool ) ), this, SLOT( onPreview( bool ) ) ) ;
240   
241   connect( buttonClose, SIGNAL( clicked() ), this, SLOT( ClickOnClose() ) ) ;
242   connect( buttonApply, SIGNAL( clicked() ), this, SLOT( ClickOnApply() ) );
243   
244   myBusy = false;
245
246   connect(view, SIGNAL(Show( QShowEvent * )), this, SLOT(onViewShow()));
247   connect(view, SIGNAL(Hide( QHideEvent * )), this, SLOT(onViewHide()));
248 }
249
250 /*!
251   Destructor
252   Destroys the object and frees any allocated resources
253 */
254 OCCViewer_ClippingDlg::~ OCCViewer_ClippingDlg()
255 {
256   // no need to delete child widgets, Qt does it all for us
257 }
258
259
260 /*!
261   Custom handling of close event: erases preview
262 */
263 void OCCViewer_ClippingDlg::closeEvent( QCloseEvent* e )
264 {
265   erasePreview();
266   
267   // Set the clipping plane back
268   Handle(V3d_View) aView3d = myView->getViewPort()->getView();
269   if ( !aView3d.IsNull() && !myClippingPlane.IsNull() )
270     aView3d->SetPlaneOn( myClippingPlane );
271   
272   myAction->setChecked( false );
273   
274   QDialog::closeEvent( e );
275 }
276
277
278 /*!
279   Custom handling of show event: displays preview
280 */
281 void OCCViewer_ClippingDlg::showEvent( QShowEvent* e )
282 {
283   ReserveClippingPlane();
284   
285   QDialog::showEvent( e );
286   onPreview( PreviewChB->isChecked() );
287 }
288
289
290 /*!
291   Custom handling of hide event: erases preview
292 */
293 void OCCViewer_ClippingDlg::hideEvent( QHideEvent* e )
294 {
295   erasePreview();
296   QDialog::hideEvent( e );
297 }
298
299
300 /*!
301   SLOT on close button click: erases preview and rejects dialog
302 */
303 void OCCViewer_ClippingDlg::ClickOnClose()
304 {
305   erasePreview();
306
307   // Set the clipping plane back
308   Handle(V3d_View) aView3d = myView->getViewPort()->getView();
309   if ( !aView3d.IsNull() && !myClippingPlane.IsNull() )
310     aView3d->SetPlaneOn( myClippingPlane );
311
312   myAction->setChecked( false );
313   
314   reject();
315 }
316
317
318 /*!
319   SLOT on apply button click: sets cutting plane
320 */
321 void OCCViewer_ClippingDlg::ClickOnApply()
322 {
323   qApp->processEvents();
324   QApplication::setOverrideCursor( Qt::WaitCursor );
325   qApp->processEvents();
326   
327   myView->setCuttingPlane( true, SpinBox_X->value() , SpinBox_Y->value() , SpinBox_Z->value(),
328                                  SpinBox_Dx->value(), SpinBox_Dy->value(), SpinBox_Dz->value() );
329   
330   QApplication::restoreOverrideCursor(); 
331   
332   erasePreview();
333   
334   ReserveClippingPlane();
335 }
336
337 /*!
338   SLOT on reset button click: sets default values
339 */
340 void OCCViewer_ClippingDlg::onReset()
341 {
342   myBusy = true;
343   SpinBox_X->setValue(0);
344   SpinBox_Y->setValue(0);
345   SpinBox_Z->setValue(0);
346   myBusy = false;
347
348   if ( PreviewChB->isChecked() )
349     {
350       erasePreview();
351       displayPreview();
352     }
353 }
354
355 /*!
356   SLOT on invert button click: inverts normal of cutting plane
357 */
358 void OCCViewer_ClippingDlg::onInvert()
359 {
360   double Dx = SpinBox_Dx->value();
361   double Dy = SpinBox_Dy->value();
362   double Dz = SpinBox_Dz->value();
363   
364   myBusy = true;
365   SpinBox_Dx->setValue( -Dx );
366   SpinBox_Dy->setValue( -Dy );
367   SpinBox_Dz->setValue( -Dz );
368   myBusy = false;
369
370   if ( PreviewChB->isChecked() )
371     {
372       erasePreview();
373       displayPreview();
374     }
375 }
376
377 /*!
378   SLOT: called on mode changed
379 */
380 void OCCViewer_ClippingDlg::onModeChanged( int mode )
381 {
382   bool isUserMode = (mode==0);
383   
384   TextLabelX->setEnabled( isUserMode );
385   TextLabelY->setEnabled( isUserMode );
386   TextLabelZ->setEnabled( isUserMode );
387
388   SpinBox_X->setEnabled( isUserMode );
389   SpinBox_Y->setEnabled( isUserMode );
390   SpinBox_Z->setEnabled( isUserMode );
391
392   TextLabelDx->setEnabled( isUserMode );
393   TextLabelDy->setEnabled( isUserMode );
394   TextLabelDz->setEnabled( isUserMode );
395
396   SpinBox_Dx->setEnabled( isUserMode );
397   SpinBox_Dy->setEnabled( isUserMode );
398   SpinBox_Dz->setEnabled( isUserMode );
399   
400   if ( isUserMode )
401     return;
402
403   double aDx = 0, aDy = 0, aDz = 0;
404
405   if ( mode == 1 )
406     {
407       aDz = 1;
408       TextLabelZ->setEnabled( true );
409       SpinBox_Z->setEnabled( true );
410       SpinBox_Z->setFocus();
411     }
412   else if ( mode == 2 )
413     {
414       aDx = 1;
415       TextLabelX->setEnabled( true );
416       SpinBox_X->setEnabled( true );
417       SpinBox_X->setFocus();
418     }
419   else if ( mode == 3 )
420     {
421       aDy = 1;
422       TextLabelY->setEnabled( true );
423       SpinBox_Y->setEnabled( true );
424       SpinBox_Y->setFocus();
425     }
426   
427   myBusy = true;
428   SpinBox_Dx->setValue( aDx );
429   SpinBox_Dy->setValue( aDy );
430   SpinBox_Dz->setValue( aDz );
431   myBusy = false;
432
433   if ( PreviewChB->isChecked() )
434     {
435       erasePreview();
436       displayPreview();
437     }
438 }
439
440
441 /*!
442   Displays preview of clipping plane
443 */
444 void OCCViewer_ClippingDlg::displayPreview()
445 {
446   if ( myBusy || !isValid() )
447     return;
448
449   OCCViewer_Viewer* anOCCViewer = (OCCViewer_Viewer*)myView->getViewManager()->getViewModel();
450   if (!anOCCViewer)
451     return;
452   
453   Handle(AIS_InteractiveContext) ic = anOCCViewer->getAISContext();
454
455   double aXMin, aYMin, aZMin, aXMax, aYMax, aZMax;
456   aXMin = aYMin = aZMin = DBL_MAX;
457   aXMax = aYMax = aZMax = -DBL_MAX;
458
459   bool isFound = false;
460   AIS_ListOfInteractive aList;
461   ic->DisplayedObjects( aList );
462   for ( AIS_ListIteratorOfListOfInteractive it( aList ); it.More(); it.Next() )
463   {
464     Handle(AIS_InteractiveObject) anObj = it.Value();
465     if ( !anObj.IsNull() && anObj->HasPresentation() &&
466          !anObj->IsKind( STANDARD_TYPE(AIS_Plane) ) )
467     {
468       Handle(Prs3d_Presentation) aPrs = anObj->Presentation();
469       if ( !aPrs->IsEmpty() && !aPrs->IsInfinite() )
470       {
471         isFound = true;
472         double xmin, ymin, zmin, xmax, ymax, zmax;
473         aPrs->MinMaxValues( xmin, ymin, zmin, xmax, ymax, zmax );
474         aXMin = qMin( aXMin, xmin );  aXMax = qMax( aXMax, xmax );
475         aYMin = qMin( aYMin, ymin );  aYMax = qMax( aYMax, ymax );
476         aZMin = qMin( aZMin, zmin );  aZMax = qMax( aZMax, zmax );
477       }
478     }
479   }
480
481   double aSize = 50;
482   
483   gp_Pnt aBasePnt( SpinBox_X->value(),  SpinBox_Y->value(),  SpinBox_Z->value() );
484   gp_Dir aNormal( SpinBox_Dx->value(), SpinBox_Dy->value(), SpinBox_Dz->value() );
485   gp_Pnt aCenter = aBasePnt;
486   
487   if ( isFound )
488     {
489       // compute clipping plane size
490       aCenter = gp_Pnt( ( aXMin + aXMax ) / 2, ( aYMin + aYMax ) / 2, ( aZMin + aZMax ) / 2 );
491       double aDiag = aCenter.Distance(gp_Pnt(aXMax, aYMax, aZMax ))*2;
492       aSize = aDiag * 1.1;
493
494       // compute clipping plane center ( redefine the base point )
495       IntAna_IntConicQuad intersector = IntAna_IntConicQuad();
496       
497       intersector.Perform( gp_Lin( aCenter, aNormal), gp_Pln( aBasePnt, aNormal), Precision::Confusion() );
498       if ( intersector.IsDone() && intersector.NbPoints() == 1 )
499         aBasePnt = intersector.Point( 1 );
500     }
501   
502   myPreviewPlane = new AIS_Plane( new Geom_Plane( aBasePnt, aNormal ) );
503   myPreviewPlane->SetSize( aSize, aSize );
504   
505   // Deactivate clipping planes
506   myView->getViewPort()->getView()->SetPlaneOff();
507
508   ic->Display( myPreviewPlane, 1, -1, false );
509   ic->SetWidth( myPreviewPlane, 10, false );
510   ic->SetMaterial( myPreviewPlane, Graphic3d_NOM_PLASTIC, false );
511   ic->SetTransparency( myPreviewPlane, 0.5, false );
512   ic->SetColor( myPreviewPlane, Quantity_Color( 85 / 255., 85 / 255., 255 / 255., Quantity_TOC_RGB ), false );
513   
514   anOCCViewer->update();
515 }
516
517
518 /*!
519   Erases preview of clipping plane
520 */
521 void OCCViewer_ClippingDlg::erasePreview ()
522 {
523   OCCViewer_Viewer* anOCCViewer = (OCCViewer_Viewer*)myView->getViewManager()->getViewModel();
524   if (!anOCCViewer)
525     return;
526   
527   Handle(AIS_InteractiveContext) ic = anOCCViewer->getAISContext();
528   
529   if ( !myPreviewPlane.IsNull() && ic->IsDisplayed( myPreviewPlane ) )
530     {
531       ic->Erase( myPreviewPlane, false, false );
532       ic->Remove( myPreviewPlane, false );
533       myPreviewPlane.Nullify();
534     }
535   
536   anOCCViewer->update();
537 }
538
539
540 /*!
541   SLOT: called on value changes (co-ordinates of point or normal)
542 */
543 void OCCViewer_ClippingDlg::onValueChanged()
544 {
545   if ( PreviewChB->isChecked() )
546     {
547       erasePreview();
548       displayPreview();
549     }
550 }
551
552
553 /*!
554   SLOT: called on preview check box toggled
555 */
556 void OCCViewer_ClippingDlg::onPreview( bool on )
557 {
558   erasePreview();
559
560   if ( on ) 
561     displayPreview();
562 }
563
564 /*!
565   \return true if plane parameters are valid
566 */
567 bool OCCViewer_ClippingDlg::isValid()
568 {
569   return ( SpinBox_Dx->value()!=0 || SpinBox_Dy->value()!=0 || SpinBox_Dz->value()!=0 );
570 }
571
572 /*!
573   Remember the current clipping plane
574 */
575 void OCCViewer_ClippingDlg::ReserveClippingPlane()
576 {
577   Handle(V3d_View) aView3d = myView->getViewPort()->getView();
578   if ( !aView3d.IsNull() )
579     {
580       aView3d->InitActivePlanes();
581       if ( aView3d->MoreActivePlanes() )
582         myClippingPlane = aView3d->ActivePlane();
583     }
584 }
585
586 void OCCViewer_ClippingDlg::onViewShow()
587 {
588   if(myAction->isChecked())
589     show();
590   else
591     hide();
592 }
593
594 void OCCViewer_ClippingDlg::onViewHide()
595 {
596   hide();
597 }
598