]> SALOME platform Git repositories - modules/gui.git/blob - src/OCCViewer/OCCViewer_ClippingDlg.cxx
Salome HOME
2c993287b88d4b1f749a61981607c80e007d97ea
[modules/gui.git] / src / OCCViewer / OCCViewer_ClippingDlg.cxx
1 // Copyright (C) 2007-2014  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 #include "OCCViewer_ClippingDlg.h"
24
25 #include <QtxDoubleSpinBox.h>
26 #include <QtxDoubleSpinSlider.h>
27 #include <QtxIntSpinSlider.h>
28 #include <QtxAction.h>
29
30 #include "SUIT_Session.h"
31 #include "SUIT_ViewWindow.h"
32 #include "SUIT_ViewManager.h"
33 #include "OCCViewer_ClipPlane.h"
34 #include "OCCViewer_ViewWindow.h"
35 #include "OCCViewer_ViewPort3d.h"
36 #include "OCCViewer_ViewModel.h"
37 #include "OCCViewer_ViewManager.h"
38 #include "OCCViewer_ClipPlaneInteractor.h"
39
40 #include <Basics_OCCTVersion.hxx>
41
42 #include <V3d_View.hxx>
43 #include <Visual3d_View.hxx>
44 #include <Geom_Plane.hxx>
45 #include <Prs3d_Presentation.hxx>
46 #include <AIS_ListIteratorOfListOfInteractive.hxx>
47 #include <AIS_ListOfInteractive.hxx>
48 #include <AIS_InteractiveObject.hxx>
49 #include <AIS_InteractiveContext.hxx>
50 #include <IntAna_IntConicQuad.hxx>
51 #include <gp_Lin.hxx>
52 #include <gp_Pln.hxx>
53 #include <math.h>
54
55 // QT Includes
56 #include <QApplication>
57 #include <QGroupBox>
58 #include <QHBoxLayout>
59 #include <QVBoxLayout>
60 #include <QGridLayout>
61 #include <QLabel>
62 #include <QPushButton>
63 #include <QComboBox>
64 #include <QCheckBox>
65 #include <QStackedLayout>
66 #include <QSlider>
67 #include <QMenu>
68
69 /**********************************************************************************
70  ************************        Internal functions        ************************
71  *********************************************************************************/
72
73 void getMinMaxFromContext( Handle(AIS_InteractiveContext) ic,
74                            double  theDefaultSize,
75                            double& theXMin,
76                            double& theYMin,
77                            double& theZMin,
78                            double& theXMax,
79                            double& theYMax,
80                            double& theZMax) {
81
82   double aXMin, aYMin, aZMin, aXMax, aYMax, aZMax;
83   aXMin = aYMin = aZMin = DBL_MAX;
84   aXMax = aYMax = aZMax = -DBL_MAX;
85   
86   bool isFound = false;
87   AIS_ListOfInteractive aList;
88   ic->DisplayedObjects( aList );
89   for ( AIS_ListIteratorOfListOfInteractive it( aList ); it.More(); it.Next() ) {
90     Handle(AIS_InteractiveObject) anObj = it.Value();
91     if ( !anObj.IsNull() && anObj->HasPresentation() &&
92          !anObj->IsKind( STANDARD_TYPE(AIS_Plane) ) ) {
93       Handle(Prs3d_Presentation) aPrs = anObj->Presentation();
94       if ( !aPrs->IsEmpty() && !aPrs->IsInfinite() ) {
95         isFound = true;
96         double xmin, ymin, zmin, xmax, ymax, zmax;
97 #if OCC_VERSION_LARGE > 0x06070100
98         Bnd_Box aBox = aPrs->MinMaxValues();
99         xmin = aBox.IsVoid() ? RealFirst() : aBox.CornerMin().X();
100         ymin = aBox.IsVoid() ? RealFirst() : aBox.CornerMin().Y();
101         zmin = aBox.IsVoid() ? RealFirst() : aBox.CornerMin().Z();
102         xmax = aBox.IsVoid() ? RealLast()  : aBox.CornerMax().X();
103         ymax = aBox.IsVoid() ? RealLast()  : aBox.CornerMax().Y();
104         zmax = aBox.IsVoid() ? RealLast()  : aBox.CornerMax().Z();
105 #else
106         aPrs->MinMaxValues( xmin, ymin, zmin, xmax, ymax, zmax );
107 #endif
108         aXMin = qMin( aXMin, xmin );  aXMax = qMax( aXMax, xmax );
109         aYMin = qMin( aYMin, ymin );  aYMax = qMax( aYMax, ymax );
110         aZMin = qMin( aZMin, zmin );  aZMax = qMax( aZMax, zmax );
111       }
112     }
113   }
114
115   if(!isFound) {
116     if(theDefaultSize == 0.0)
117       theDefaultSize = 100.;
118     aXMin = aYMin = aZMin = -theDefaultSize;
119     aXMax = aYMax = aZMax = theDefaultSize;
120   }
121   theXMin = aXMin;theYMin = aYMin;theZMin = aZMin;
122   theXMax = aXMax;theYMax = aYMax;theZMax = aZMax;
123 }
124
125 /*!
126   Compute the point of bounding box and current clipping plane
127  */
128 void ComputeBoundsParam( const double theBounds[6],
129                          const double theDirection[3],
130                          double theMinPnt[3],
131                          double& theMaxBoundPrj,
132                          double& theMinBoundPrj )
133 {
134   double aEnlargeBounds[6];
135
136   // Enlarge bounds in order to avoid conflicts of precision
137   for(int i = 0; i < 6; i += 2)
138   {
139     static double EPS = 1.0E-3;
140     double aDelta = (theBounds[i+1] - theBounds[i])*EPS;
141     aEnlargeBounds[i  ] = theBounds[i  ] - aDelta;
142     aEnlargeBounds[i+1] = theBounds[i+1] + aDelta;
143   }
144
145   double aBoundPoints[8][3] = { { aEnlargeBounds[0], aEnlargeBounds[2], aEnlargeBounds[4] },
146                                 { aEnlargeBounds[1], aEnlargeBounds[2], aEnlargeBounds[4] },
147                                 { aEnlargeBounds[0], aEnlargeBounds[3], aEnlargeBounds[4] },
148                                 { aEnlargeBounds[1], aEnlargeBounds[3], aEnlargeBounds[4] },
149                                 { aEnlargeBounds[0], aEnlargeBounds[2], aEnlargeBounds[5] },
150                                 { aEnlargeBounds[1], aEnlargeBounds[2], aEnlargeBounds[5] },
151                                 { aEnlargeBounds[0], aEnlargeBounds[3], aEnlargeBounds[5] },
152                                 { aEnlargeBounds[1], aEnlargeBounds[3], aEnlargeBounds[5] } };
153
154   int aMaxId = 0;
155   theMaxBoundPrj = theDirection[0] * aBoundPoints[aMaxId][0] + theDirection[1] * aBoundPoints[aMaxId][1]
156                    + theDirection[2] * aBoundPoints[aMaxId][2];
157   theMinBoundPrj = theMaxBoundPrj;
158   for(int i = 1; i < 8; i++) {
159     double aTmp = theDirection[0] * aBoundPoints[i][0] + theDirection[1] * aBoundPoints[i][1]
160                   + theDirection[2] * aBoundPoints[i][2];
161     if(theMaxBoundPrj < aTmp) {
162       theMaxBoundPrj = aTmp;
163       aMaxId = i;
164     }
165     if(theMinBoundPrj > aTmp) {
166       theMinBoundPrj = aTmp;
167     }
168   }
169   double *aMinPnt = aBoundPoints[aMaxId];
170   theMinPnt[0] = aMinPnt[0];
171   theMinPnt[1] = aMinPnt[1];
172   theMinPnt[2] = aMinPnt[2];
173 }
174
175 /*!
176   Compute the position of current plane by distance
177  */
178 void DistanceToPosition( const double theBounds[6],
179                          const double theDirection[3],
180                          const double theDist,
181                          double thePos[3] )
182 {
183   double aMaxBoundPrj, aMinBoundPrj, aMinPnt[3];
184   ComputeBoundsParam( theBounds, theDirection, aMinPnt, aMaxBoundPrj, aMinBoundPrj );
185   double aLength = (aMaxBoundPrj - aMinBoundPrj) * theDist;
186   thePos[0] = aMinPnt[0] - theDirection[0] * aLength;
187   thePos[1] = aMinPnt[1] - theDirection[1] * aLength;
188   thePos[2] = aMinPnt[2] - theDirection[2] * aLength;
189 }
190
191 /*!
192   Compute the parameters of clipping plane
193  */
194 bool ComputeClippingPlaneParameters( const Handle(AIS_InteractiveContext)& theIC,
195                                      const double theDefaultSize,
196                                      const double theNormal[3],
197                                      const double theDist,
198                                      double theOrigin[3] )
199 {
200   double aBounds[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
201
202   getMinMaxFromContext( theIC, theDefaultSize, aBounds[0], aBounds[2], aBounds[4], aBounds[1], aBounds[3], aBounds[5] );
203
204   DistanceToPosition( aBounds, theNormal, theDist, theOrigin );
205   return true;
206 }
207
208 /*!
209   \brief Converts relative plane parameters to absolute.
210   \param theIC [in] the interactive context.
211   \param theDefaultSize [in] the default trihedron size.
212   \param theDistance [in] the plane distance relative to minimum corner of model boundaries.
213   \param theDX [in] x component of plane direction.
214   \param theDY [in] y component of plane direction.
215   \param theDZ [in] z component of plane direction.
216   \param theX [out] x coordinate of plane origin.
217   \param theY [out] y coordinate of plane origin.
218   \param theZ [out] z coordinate of plane origin.
219  */
220 bool DistanceToXYZ ( const Handle(AIS_InteractiveContext)& theIC,
221                      const double theDefaultSize,
222                      const double theDistance,
223                      const double theDX,
224                      const double theDY,
225                      const double theDZ,
226                      double& theX,
227                      double& theY,
228                      double& theZ )
229 {
230   double aNormal[3] = { theDX, theDY, theDZ };
231   double anOrigin[3] = { 0.0, 0.0, 0.0 };
232
233   bool anIsOk = ComputeClippingPlaneParameters( theIC, theDefaultSize, aNormal, theDistance, anOrigin );
234
235   if( !anIsOk )
236   {
237     return false;
238   }
239
240   theX = anOrigin[0];
241   theY = anOrigin[1];
242   theZ = anOrigin[2];
243
244   return true;
245 }
246
247 /*!
248   \brief Converts absolute position and direction to bounding box distance.
249   \param theIC [in] the interactive context.
250   \param theDefaultSize [in] the default trihedron size.
251   \param theX [in] x coordinate of plane origin.
252   \param theY [in] y coordinate of plane origin.
253   \param theZ [in] z coordinate of plane origin.
254   \param theDX [in] x component of plane direction.
255   \param theDY [in] y component of plane direction.
256   \param theDZ [in] z component of plane direction.
257   \param theDistance [out] the plane distance relative to minimum corner of model boundaries.
258  */
259 void XYZToDistance ( const Handle(AIS_InteractiveContext)& theIC,
260                      const double theDefaultSize,
261                      const double theX,
262                      const double theY,
263                      const double theZ,
264                      const double theDX,
265                      const double theDY,
266                      const double theDZ,
267                      double& theDistance )
268 {
269   gp_Pnt aPlaneP( theX, theY, theZ );
270   gp_Dir aPlaneN( theDX, theDY, theDZ );
271
272   double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
273
274   getMinMaxFromContext( theIC, theDefaultSize, aXmin, aYmin, aZmin, aXmax, aYmax, aZmax );
275
276   Bnd_Box aMinMax;
277   aMinMax.Update( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax );
278
279   gp_Trsf aRelativeTransform;
280   aRelativeTransform.SetTransformation( gp_Ax3(), gp_Ax3( aPlaneP, aPlaneN ) );
281   Bnd_Box aRelativeBounds = aMinMax.Transformed( aRelativeTransform );
282
283   aRelativeBounds.Get( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax );
284
285   double aLength   = aZmax - aZmin;
286   double aDistance = aZmax;
287
288   double aRelativeDistance = aLength > 0.01 ? aDistance / aLength : 0.0;
289   aRelativeDistance = qMin( aRelativeDistance, aLength );
290   aRelativeDistance = qMax( aRelativeDistance, 0.0 );
291   theDistance = aRelativeDistance;
292 }
293
294 /*!
295   Compute clipping plane size base point and normal
296  */
297
298 void clipPlaneParams(OCCViewer_ClipPlane& theClipPlane, Handle(AIS_InteractiveContext) theContext,
299                      double& theSize, gp_Pnt& theBasePnt, gp_Dir& theNormal, double defaultSize) {
300   double aXMin, aYMin, aZMin, aXMax, aYMax, aZMax;
301   aXMin = aYMin = aZMin = DBL_MAX;
302   aXMax = aYMax = aZMax = -DBL_MAX;
303   
304   getMinMaxFromContext(theContext,defaultSize,aXMin, aYMin, aZMin, aXMax, aYMax, aZMax);
305   double aSize = 50;
306
307   double aNormalX = 0.0;
308   double aNormalY = 0.0;
309   double aNormalZ = 0.0;
310   theClipPlane.OrientationToXYZ( aNormalX, aNormalY, aNormalZ );
311   gp_Pnt aBasePnt( theClipPlane.X, theClipPlane.Y, theClipPlane.Z );
312   gp_Dir aNormal( aNormalX, aNormalY, aNormalZ );
313
314   // compute clipping plane size
315   gp_Pnt aCenter = gp_Pnt( ( aXMin + aXMax ) / 2, ( aYMin + aYMax ) / 2, ( aZMin + aZMax ) / 2 );
316   double aDiag = aCenter.Distance( gp_Pnt( aXMax, aYMax, aZMax ) )*2;
317   aSize = aDiag * 1.1;
318   
319   // compute clipping plane center ( redefine the base point )
320   IntAna_IntConicQuad intersector = IntAna_IntConicQuad();
321   
322   intersector.Perform( gp_Lin( aCenter, aNormal), gp_Pln( aBasePnt, aNormal), Precision::Confusion() );
323
324   if ( intersector.IsDone() && intersector.NbPoints() == 1 )
325     aBasePnt = intersector.Point( 1 );
326   
327   theSize = aSize;
328   theBasePnt = aBasePnt;
329   theNormal = aNormal;
330 }
331
332
333 /*********************************************************************************
334  *********************      class OCCViewer_ClippingDlg      *********************
335  *********************************************************************************/
336 /*!
337   Constructor
338   \param view - view window
339   \param parent - parent widget
340 */
341 OCCViewer_ClippingDlg::OCCViewer_ClippingDlg(OCCViewer_ViewWindow* parent , OCCViewer_Viewer* model)
342   : QDialog( parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint )
343 {
344   setObjectName( "OCCViewer_ClippingDlg" );
345   setModal( false );
346
347   setWindowTitle( tr( "Clipping" ) );
348
349   setAttribute (Qt::WA_DeleteOnClose, true);
350   
351   QVBoxLayout* topLayout = new QVBoxLayout( this );
352   topLayout->setMargin( 11 ); topLayout->setSpacing( 6 );
353
354   /***************************************************************/
355   // Controls for selecting, creating, deleting planes
356   QGroupBox* GroupPlanes = new QGroupBox( tr("CLIPPING_PLANES"), this );
357   QHBoxLayout* GroupPlanesLayout = new QHBoxLayout( GroupPlanes );
358   ComboBoxPlanes = new QComboBox( GroupPlanes );
359   isActivePlane = new QCheckBox( tr("IS_ACTIVE_PLANE"), this );
360   buttonNew = new QPushButton( tr("BTN_NEW"), GroupPlanes );
361   buttonDelete = new QPushButton( tr("BTN_DELETE"), GroupPlanes );
362   buttonDisableAll = new QPushButton( tr("BTN_DISABLE_ALL"), GroupPlanes );
363   MenuMode = new QMenu( "MenuMode", buttonNew );
364   MenuMode->addAction( tr( "ABSOLUTE" ), this, SLOT( onModeAbsolute() ) );
365   MenuMode->addAction( tr( "RELATIVE" ), this, SLOT( onModeRelative() ) );
366   buttonNew->setMenu( MenuMode );
367
368   GroupPlanesLayout->addWidget( ComboBoxPlanes );
369   GroupPlanesLayout->addWidget( isActivePlane );
370   GroupPlanesLayout->addWidget( buttonNew );
371   GroupPlanesLayout->addWidget( buttonDelete );
372   GroupPlanesLayout->addWidget( buttonDisableAll );
373
374   ModeStackedLayout = new QStackedLayout();
375
376   /**********************   Mode Absolute   **********************/
377   /* Controls for absolute mode of clipping plane:
378      X, Y, Z - coordinates of the intersection of cutting plane and the three axes
379      Dx, Dy, Dz - components of normal to the cutting plane
380      Orientation - direction of cutting plane
381    */
382   const double min = -1e+7;
383   const double max =  1e+7;
384   const double step = 5;
385   const int precision = -7;
386
387   // Croup Point
388   QGroupBox* GroupAbsolutePoint = new QGroupBox( this );
389   GroupAbsolutePoint->setObjectName( "GroupPoint" );
390   GroupAbsolutePoint->setTitle( tr("BASE_POINT") );
391   QGridLayout* GroupPointLayout = new QGridLayout( GroupAbsolutePoint );
392   GroupPointLayout->setAlignment( Qt::AlignTop );
393   GroupPointLayout->setSpacing( 6 ); GroupPointLayout->setMargin( 11 );
394
395   TextLabelX = new QLabel( GroupAbsolutePoint );
396   TextLabelX->setObjectName( "TextLabelX" );
397   TextLabelX->setText( tr("X:") );
398   GroupPointLayout->addWidget( TextLabelX, 0, 0 );
399   
400   SpinBox_X = new QtxDoubleSpinBox( min, max, step, GroupAbsolutePoint );
401   SpinBox_X->setObjectName("SpinBox_X" );
402   SpinBox_X->setPrecision( precision );
403   GroupPointLayout->addWidget( SpinBox_X, 0, 1 );
404
405   TextLabelY = new QLabel( GroupAbsolutePoint );
406   TextLabelY->setObjectName( "TextLabelY" );
407   TextLabelY->setText( tr("Y:") );
408   GroupPointLayout->addWidget( TextLabelY, 0, 2 );
409
410   SpinBox_Y = new QtxDoubleSpinBox( min, max, step, GroupAbsolutePoint );
411   SpinBox_Y->setObjectName("SpinBox_Y" );
412   SpinBox_Y->setPrecision( precision );
413   GroupPointLayout->addWidget( SpinBox_Y, 0, 3 );
414
415   TextLabelZ = new QLabel( GroupAbsolutePoint );
416   TextLabelZ->setObjectName( "TextLabelZ" );
417   TextLabelZ->setText( tr("Z:") );
418   GroupPointLayout->addWidget( TextLabelZ, 0, 4 );
419
420   SpinBox_Z = new QtxDoubleSpinBox( min, max, step, GroupAbsolutePoint );
421   SpinBox_Z->setObjectName("SpinBox_Z" );
422   SpinBox_Z->setPrecision( precision );
423   GroupPointLayout->addWidget( SpinBox_Z, 0, 5 );
424
425   resetButton  = new QPushButton( GroupAbsolutePoint );
426   resetButton->setObjectName( "resetButton" );
427   resetButton->setText( tr( "RESET"  ) );
428   GroupPointLayout->addWidget( resetButton, 0, 6 );
429
430   // Group Direction
431   GroupAbsoluteDirection = new QGroupBox( this );
432   GroupAbsoluteDirection->setObjectName( "GroupDirection" );
433   GroupAbsoluteDirection->setTitle( tr("DIRECTION") );
434   QGridLayout* GroupDirectionLayout = new QGridLayout( GroupAbsoluteDirection );
435   GroupDirectionLayout->setAlignment( Qt::AlignTop );
436   GroupDirectionLayout->setSpacing( 6 );
437   GroupDirectionLayout->setMargin( 11 );
438   
439   TextLabelDx = new QLabel( GroupAbsoluteDirection );
440   TextLabelDx->setObjectName( "TextLabelDx" );
441   TextLabelDx->setText( tr("Dx:") );
442   GroupDirectionLayout->addWidget( TextLabelDx, 0, 0 );
443   
444   SpinBox_Dx = new QtxDoubleSpinBox( min, max, step, GroupAbsoluteDirection );
445   SpinBox_Dx->setObjectName("SpinBox_Dx" );
446   SpinBox_Dx->setPrecision( precision );
447   GroupDirectionLayout->addWidget( SpinBox_Dx, 0, 1 );
448
449   TextLabelDy = new QLabel( GroupAbsoluteDirection );
450   TextLabelDy->setObjectName( "TextLabelDy" );
451   TextLabelDy->setText( tr("Dy:") );
452   GroupDirectionLayout->addWidget( TextLabelDy, 0, 2 );
453   
454   SpinBox_Dy = new QtxDoubleSpinBox( min, max, step, GroupAbsoluteDirection );
455   SpinBox_Dy->setObjectName("SpinBox_Dy" );
456   SpinBox_Dy->setPrecision( precision );
457   GroupDirectionLayout->addWidget( SpinBox_Dy, 0, 3 );
458
459   TextLabelDz = new QLabel( GroupAbsoluteDirection );
460   TextLabelDz->setObjectName( "TextLabelDz" );
461   TextLabelDz->setText( tr("Dz:") );
462   GroupDirectionLayout->addWidget( TextLabelDz, 0, 4 );
463   
464   SpinBox_Dz = new QtxDoubleSpinBox( min, max, step, GroupAbsoluteDirection );
465   SpinBox_Dz->setObjectName("SpinBox_Dz" );
466   SpinBox_Dz->setPrecision( precision );
467   GroupDirectionLayout->addWidget( SpinBox_Dz, 0, 5 );
468
469   invertButton  = new QPushButton( GroupAbsoluteDirection );
470   invertButton->setObjectName( "invertButton" );
471   invertButton->setText( tr( "INVERT"  ) );
472   GroupDirectionLayout->addWidget( invertButton, 0, 6 );
473  
474   CBAbsoluteOrientation = new QComboBox( GroupAbsoluteDirection );
475   CBAbsoluteOrientation->setObjectName( "AbsoluteOrientation" );
476   CBAbsoluteOrientation->insertItem( CBAbsoluteOrientation->count(), tr( "CUSTOM" ) );
477   CBAbsoluteOrientation->insertItem( CBAbsoluteOrientation->count(), tr( "||X-Y" ) );
478   CBAbsoluteOrientation->insertItem( CBAbsoluteOrientation->count(), tr( "||Y-Z" ) );
479   CBAbsoluteOrientation->insertItem( CBAbsoluteOrientation->count(), tr( "||Z-X" ) );
480   GroupDirectionLayout->addWidget( CBAbsoluteOrientation, 1, 0, 1, 6 );
481
482   QVBoxLayout* ModeActiveLayout = new QVBoxLayout();
483   ModeActiveLayout->setMargin( 11 ); ModeActiveLayout->setSpacing( 6 );
484   ModeActiveLayout->addWidget( GroupAbsolutePoint );
485   ModeActiveLayout->addWidget( GroupAbsoluteDirection );
486
487   QWidget* ModeActiveWidget = new QWidget( this );
488   ModeActiveWidget->setLayout( ModeActiveLayout );
489
490   /**********************   Mode Relative   **********************/
491   /* Controls for relative mode of clipping plane:
492      Distance - Value from 0 to 1.
493      Specifies the distance from the minimum value in a given direction of bounding box to the current position
494      Rotation1, Rotation2 - turn angles of cutting plane in given directions
495      Orientation - direction of cutting plane
496    */
497   QGroupBox* GroupParameters = new QGroupBox( tr("PARAMETERS"), this );
498   QGridLayout* GroupParametersLayout = new QGridLayout( GroupParameters );
499   GroupParametersLayout->setMargin( 11 ); GroupParametersLayout->setSpacing( 6 );
500
501   TextLabelOrientation = new QLabel( tr("ORIENTATION"), GroupParameters);
502   TextLabelOrientation->setObjectName( "TextLabelOrientation" );
503   GroupParametersLayout->addWidget( TextLabelOrientation, 0, 0 );
504
505   CBRelativeOrientation = new QComboBox(GroupParameters);
506   CBRelativeOrientation->setObjectName( "RelativeOrientation" );
507   CBRelativeOrientation->addItem( tr("ALONG_XY") );
508   CBRelativeOrientation->addItem( tr("ALONG_YZ") );
509   CBRelativeOrientation->addItem( tr("ALONG_ZX") );
510   GroupParametersLayout->addWidget( CBRelativeOrientation, 0, 1 );
511
512   TextLabelDistance = new QLabel( tr("DISTANCE"), GroupParameters );
513   TextLabelDistance->setObjectName( "TextLabelDistance" );
514   GroupParametersLayout->addWidget( TextLabelDistance, 1, 0 );
515   
516   SpinSliderDistance = new QtxDoubleSpinSlider( 0., 1., 0.01, GroupParameters );
517   SpinSliderDistance->setObjectName( "SpinSliderDistance" );
518   SpinSliderDistance->setPrecision( precision );
519   QFont fnt = SpinSliderDistance->font(); fnt.setBold( true ); SpinSliderDistance->setFont( fnt );
520   GroupParametersLayout->addWidget( SpinSliderDistance, 1, 1 );
521
522   QString aUnitRot = "\xB0";
523
524   TextLabelRotation1 = new QLabel( tr("ROTATION_AROUND_X_Y2Z"), GroupParameters );
525   TextLabelRotation1->setObjectName( "TextLabelRotation1" );
526   GroupParametersLayout->addWidget( TextLabelRotation1, 2, 0 );
527   
528   SpinSliderRotation1 = new QtxIntSpinSlider( -180, 180, 1, GroupParameters );
529   SpinSliderRotation1->setObjectName( "SpinSliderRotation1" );
530   SpinSliderRotation1->setUnit( aUnitRot );
531   SpinSliderRotation1->setFont( fnt );
532   GroupParametersLayout->addWidget( SpinSliderRotation1, 2, 1 );
533
534   TextLabelRotation2 = new QLabel(tr("ROTATION_AROUND_Y_X2Z"), GroupParameters);
535   TextLabelRotation2->setObjectName( "TextLabelRotation2" );
536   TextLabelRotation2->setObjectName( "TextLabelRotation2" );
537   GroupParametersLayout->addWidget( TextLabelRotation2, 3, 0 );
538
539   SpinSliderRotation2 = new QtxIntSpinSlider( -180, 180, 1, GroupParameters );
540   SpinSliderRotation2->setObjectName( "SpinSliderRotation2" );
541   SpinSliderRotation2->setUnit( aUnitRot );
542   SpinSliderRotation2->setFont( fnt );
543   GroupParametersLayout->addWidget( SpinSliderRotation2, 3, 1 );
544
545   /***************************************************************/
546   QGroupBox* CheckBoxWidget = new QGroupBox( this );
547   QHBoxLayout* CheckBoxLayout = new QHBoxLayout( CheckBoxWidget );
548   
549   PreviewCheckBox = new QCheckBox( tr("PREVIEW"), CheckBoxWidget );
550   PreviewCheckBox->setObjectName( "PreviewCheckBox" );
551   PreviewCheckBox->setChecked( true );
552   CheckBoxLayout->addWidget( PreviewCheckBox, 0, Qt::AlignCenter );
553   
554   AutoApplyCheckBox = new QCheckBox( tr("AUTO_APPLY"), CheckBoxWidget );
555   AutoApplyCheckBox->setObjectName( "AutoApplyCheckBox" );
556   CheckBoxLayout->addWidget( AutoApplyCheckBox, 0, Qt::AlignCenter );
557
558   /***************************************************************/
559   QGroupBox* GroupButtons = new QGroupBox( this );
560   QHBoxLayout* GroupButtonsLayout = new QHBoxLayout( GroupButtons );
561   GroupButtonsLayout->setAlignment( Qt::AlignTop );
562   GroupButtonsLayout->setMargin( 11 ); GroupButtonsLayout->setSpacing( 6 );
563   
564   buttonOk = new QPushButton( GroupButtons );
565   buttonOk->setObjectName( "buttonOk" );
566   buttonOk->setText( tr( "BUT_APPLY_AND_CLOSE"  ) );
567   buttonOk->setAutoDefault( TRUE );
568   buttonOk->setDefault( TRUE );
569   GroupButtonsLayout->addWidget( buttonOk );
570
571   buttonApply = new QPushButton( GroupButtons );
572   buttonApply->setObjectName( "buttonApply" );
573   buttonApply->setText( tr( "BUT_APPLY"  ) );
574   buttonApply->setAutoDefault( TRUE );
575   buttonApply->setDefault( TRUE );
576   GroupButtonsLayout->addWidget( buttonApply );
577
578   GroupButtonsLayout->addStretch();
579   
580   buttonClose = new QPushButton( GroupButtons );
581   buttonClose->setObjectName( "buttonClose" );
582   buttonClose->setText( tr( "BUT_CLOSE"  ) );
583   buttonClose->setAutoDefault( TRUE );
584   GroupButtonsLayout->addWidget( buttonClose );
585
586   QPushButton* buttonHelp = new QPushButton( tr( "HELP" ), GroupButtons );
587   buttonHelp->setAutoDefault( TRUE );
588   GroupButtonsLayout->addWidget( buttonHelp );
589
590   /***************************************************************/
591   ModeStackedLayout->addWidget( ModeActiveWidget );
592   ModeStackedLayout->addWidget( GroupParameters );
593
594   topLayout->addWidget( GroupPlanes );
595   topLayout->addLayout( ModeStackedLayout );
596   topLayout->addWidget( CheckBoxWidget );
597   topLayout->addWidget( GroupButtons );
598
599   this->setLayout( topLayout );
600
601   // Initializations
602   initParam();
603
604   // Signals and slots connections
605   connect( ComboBoxPlanes, SIGNAL( activated( int ) ), this, SLOT( onSelectPlane( int ) ) );
606   connect( isActivePlane,  SIGNAL ( toggled ( bool ) ),  this, SLOT( onValueChanged() ) );
607   connect( buttonNew, SIGNAL( clicked() ), buttonNew, SLOT( showMenu() ) );
608   connect( buttonDelete, SIGNAL( clicked() ), this, SLOT( ClickOnDelete() ) );
609   connect( buttonDisableAll, SIGNAL( clicked() ), this, SLOT( ClickOnDisableAll() ) );
610
611   connect( resetButton,  SIGNAL (clicked() ), this, SLOT( onReset() ) );
612   connect( invertButton, SIGNAL (clicked() ), this, SLOT( onInvert() ) ) ;
613   connect( SpinBox_X,  SIGNAL ( valueChanged( double ) ),  this, SLOT( onValueChanged() ) );
614   connect( SpinBox_Y,  SIGNAL ( valueChanged( double ) ),  this, SLOT( onValueChanged() ) );
615   connect( SpinBox_Z,  SIGNAL ( valueChanged( double ) ),  this, SLOT( onValueChanged() ) );
616   connect( SpinBox_Dx, SIGNAL ( valueChanged( double ) ),  this, SLOT( onValueChanged() ) );
617   connect( SpinBox_Dy, SIGNAL ( valueChanged( double ) ),  this, SLOT( onValueChanged() ) );
618   connect( SpinBox_Dz, SIGNAL ( valueChanged( double ) ),  this, SLOT( onValueChanged() ) );
619   connect( CBAbsoluteOrientation, SIGNAL ( activated ( int ) ), this, SLOT( onOrientationAbsoluteChanged( int ) ) ) ;
620
621   connect( CBRelativeOrientation, SIGNAL( activated( int ) ), this, SLOT( onOrientationRelativeChanged( int ) ) );
622   connect( SpinSliderDistance, SIGNAL( valueChanged( double ) ),  this, SLOT( onValueChanged() ) );
623   connect( SpinSliderRotation1, SIGNAL( valueChanged( int ) ), this, SLOT( onValueChanged() ) );
624   connect( SpinSliderRotation2, SIGNAL( valueChanged( int ) ), this, SLOT( onValueChanged() ) );
625
626   connect( PreviewCheckBox, SIGNAL ( toggled ( bool ) ), this, SLOT( onPreview( bool ) ) ) ;
627   connect( AutoApplyCheckBox, SIGNAL ( toggled( bool ) ), this, SLOT( onAutoApply( bool ) ) );
628   
629   connect( buttonClose, SIGNAL( clicked() ), this, SLOT( ClickOnClose() ) ) ;
630   connect( buttonOk, SIGNAL( clicked() ), this, SLOT( ClickOnOk() ) );
631   connect( buttonApply, SIGNAL( clicked() ), this, SLOT( ClickOnApply() ) );
632   connect( buttonHelp, SIGNAL( clicked() ), this, SLOT( ClickOnHelp() ) );
633
634   myBusy = false;
635   myIsSelectPlane = false;
636   myIsPlaneCreation = false;
637   myIsUpdatingControls = false;
638   myModel = model;
639
640   myModel->getViewer3d()->InitActiveViews();
641
642   OCCViewer_ViewManager* aViewMgr = (OCCViewer_ViewManager*) myModel->getViewManager();
643   myInteractor = new OCCViewer_ClipPlaneInteractor( aViewMgr, this );
644   connect( myInteractor, SIGNAL( planeClicked( const Handle_AIS_Plane& ) ), SLOT( onPlaneClicked( const Handle_AIS_Plane& ) ) );
645   connect( myInteractor, SIGNAL( planeDragged( const Handle_AIS_Plane& ) ), SLOT( onPlaneDragged( const Handle_AIS_Plane& ) ) );
646
647   myLocalPlanes = myModel->getClipPlanes();
648   synchronize();
649 }
650
651 /*!
652   Destructor
653   Destroys the object and frees any allocated resources
654 */
655 OCCViewer_ClippingDlg::~OCCViewer_ClippingDlg()
656 {
657   myLocalPlanes.clear();
658 }
659
660 /*!
661   Custom handling of close event: erases preview
662 */
663 void OCCViewer_ClippingDlg::closeEvent( QCloseEvent* e )
664 {
665   erasePreview();
666   QDialog::closeEvent( e );
667   OCCViewer_ViewWindow* v = qobject_cast<OCCViewer_ViewWindow*>(parent());
668   if(v)
669     v->onClipping(false);
670 }
671
672 /*!
673   Custom handling of show event: displays preview
674 */
675 void OCCViewer_ClippingDlg::showEvent( QShowEvent* e )
676 {
677   QDialog::showEvent( e );
678   onPreview( PreviewCheckBox->isChecked() );
679 }
680
681 /*!
682   Custom handling of hide event: erases preview
683 */
684 void OCCViewer_ClippingDlg::hideEvent( QHideEvent* e )
685 {
686   erasePreview();
687   QDialog::hideEvent( e );
688   OCCViewer_ViewWindow* v = qobject_cast<OCCViewer_ViewWindow*>(parent());
689   if(v)
690     v->onClipping(false);
691
692 }
693
694 /*!
695   Initialization of initial values of widgets
696 */
697 void OCCViewer_ClippingDlg::initParam()
698 {
699   SpinBox_X->setValue( 0.0 );
700   SpinBox_Y->setValue( 0.0 );
701   SpinBox_Z->setValue( 0.0 );
702
703   SpinBox_Dx->setValue( 1.0 );
704   SpinBox_Dy->setValue( 1.0 );
705   SpinBox_Dz->setValue( 1.0 );
706
707   CBAbsoluteOrientation->setCurrentIndex(0);
708
709   SpinSliderDistance->setValue( 0.5 );
710   SpinSliderRotation1->setValue( 0 );
711   SpinSliderRotation2->setValue( 0 );
712   CBRelativeOrientation->setCurrentIndex( 0 );
713
714   isActivePlane->setChecked( true );
715 }
716
717 /*!
718   Set plane parameters from widgets.
719 */
720 void OCCViewer_ClippingDlg::setPlaneParam( OCCViewer_ClipPlane& thePlane )
721 {
722   OCCViewer_ClipPlane::PlaneMode aMode = currentPlaneMode();
723
724   thePlane.Mode = aMode;
725
726   if ( aMode == OCCViewer_ClipPlane::Absolute )
727   {
728     if( qFuzzyIsNull( SpinBox_Dx->value() ) && 
729         qFuzzyIsNull( SpinBox_Dy->value() ) && 
730         qFuzzyIsNull( SpinBox_Dz->value() ) ) {
731       return;
732     }
733   }
734
735   thePlane.OrientationType = (aMode == OCCViewer_ClipPlane::Absolute)
736     ? CBAbsoluteOrientation->currentIndex()
737     : CBRelativeOrientation->currentIndex();
738
739   // Get XYZ, DXYZ
740   if ( aMode == OCCViewer_ClipPlane::Absolute )
741   {
742     if ( thePlane.OrientationType == OCCViewer_ClipPlane::AbsoluteCustom )
743     {
744       thePlane.AbsoluteOrientation.Dx = SpinBox_Dx->value();
745       thePlane.AbsoluteOrientation.Dy = SpinBox_Dy->value();
746       thePlane.AbsoluteOrientation.Dz = SpinBox_Dz->value();
747     }
748     else
749     {
750       thePlane.AbsoluteOrientation.IsInvert = SpinBox_Dx->value() < 0.0
751                                            || SpinBox_Dy->value() < 0.0
752                                            || SpinBox_Dz->value() < 0.0;
753     }
754
755     thePlane.X = SpinBox_X->value();
756     thePlane.Y = SpinBox_Y->value();
757     thePlane.Z = SpinBox_Z->value();
758   }
759   else
760   {
761     thePlane.RelativeOrientation.Rotation1 = SpinSliderRotation1->value();
762     thePlane.RelativeOrientation.Rotation2 = SpinSliderRotation2->value();
763
764     double aPlaneDx = 0.0;
765     double aPlaneDy = 0.0;
766     double aPlaneDz = 0.0;
767     double aX = 0.0;
768     double aY = 0.0;
769     double aZ = 0.0;
770
771     OCCViewer_ClipPlane::RelativeToDXYZ( thePlane.OrientationType,
772                                          thePlane.RelativeOrientation.Rotation1,
773                                          thePlane.RelativeOrientation.Rotation2,
774                                          aPlaneDx, aPlaneDy, aPlaneDz );
775
776     DistanceToXYZ( myModel->getAISContext(),
777                    myModel->trihedronSize(),
778                    SpinSliderDistance->value(),
779                    aPlaneDx, aPlaneDy, aPlaneDz,
780                    aX, aY, aZ );
781
782     thePlane.X = aX;
783     thePlane.Y = aY;
784     thePlane.Z = aZ;
785   }
786
787   thePlane.IsOn = isActivePlane->isChecked();
788 }
789
790 /*!
791   Synchronize dialog's widgets with data
792 */
793 void OCCViewer_ClippingDlg::synchronize()
794 {
795   ComboBoxPlanes->clear();
796   int aNbPlanesAbsolute = myLocalPlanes.size();
797
798   QString aName;
799   for(int i = 1; i<=aNbPlanesAbsolute; i++ ) {
800     aName = QString("Plane %1").arg(i);
801     ComboBoxPlanes->addItem( aName );
802   }
803
804   int aPos = ComboBoxPlanes->count() - 1;
805   ComboBoxPlanes->setCurrentIndex( aPos );
806
807   bool anIsControlsEnable = ( aPos >= 0 );
808   if ( anIsControlsEnable ) {
809     onSelectPlane( aPos );
810   }
811   else {
812     ComboBoxPlanes->addItem( tr( "NO_PLANES" ) );
813     initParam();
814   }
815   if ( currentPlaneMode() == OCCViewer_ClipPlane::Absolute )
816   {
817     SpinBox_X->setEnabled( anIsControlsEnable );
818     SpinBox_Y->setEnabled( anIsControlsEnable );
819     SpinBox_Z->setEnabled( anIsControlsEnable );
820     SpinBox_Dx->setEnabled( anIsControlsEnable );
821     SpinBox_Dy->setEnabled( anIsControlsEnable );
822     SpinBox_Dz->setEnabled( anIsControlsEnable );
823     CBAbsoluteOrientation->setEnabled( anIsControlsEnable );
824     invertButton->setEnabled( anIsControlsEnable );
825     resetButton->setEnabled( anIsControlsEnable );
826   }
827   else if ( currentPlaneMode() == OCCViewer_ClipPlane::Relative )
828   {
829     CBRelativeOrientation->setEnabled( anIsControlsEnable );
830     SpinSliderDistance->setEnabled( anIsControlsEnable );
831     SpinSliderRotation1->setEnabled( anIsControlsEnable );
832     SpinSliderRotation2->setEnabled( anIsControlsEnable );
833     isActivePlane->setEnabled( anIsControlsEnable );
834   }
835   isActivePlane->setEnabled( anIsControlsEnable );
836 }
837
838 /*!
839   Displays preview of clipping plane
840 */
841 void OCCViewer_ClippingDlg::displayPreview()
842 {
843   if ( myBusy || !isValid() || !myModel)
844     return;
845
846   Handle(AIS_InteractiveContext) ic = myModel->getAISContext();
847   
848   int aCurPlaneIndex = ComboBoxPlanes->currentIndex();
849
850   for ( int i=0; i < clipPlanesCount(); i++ ) {
851     OCCViewer_ClipPlane& aClipPlane = getClipPlane(i);
852     if ( aClipPlane.IsOn ) {
853       Handle(AIS_Plane) myPreviewPlane;
854       double aSize;
855       gp_Pnt aBasePnt;
856       gp_Dir aNormal;
857       clipPlaneParams(aClipPlane, ic, aSize, aBasePnt, aNormal, myModel->trihedronSize());
858       myPreviewPlane = new AIS_Plane( new Geom_Plane( aBasePnt, aNormal ), aBasePnt );
859       myPreviewPlane->SetTypeOfSensitivity( Select3D_TOS_INTERIOR );
860       myPreviewPlane->SetSize( aSize, aSize );
861       ic->SetWidth( myPreviewPlane, 10, false );
862       ic->SetMaterial( myPreviewPlane, Graphic3d_NOM_PLASTIC, false );
863       ic->SetTransparency( myPreviewPlane, 0.5, false );
864       Quantity_Color c = (aCurPlaneIndex == i) ? Quantity_Color( 255. / 255., 70. / 255., 0. / 255., Quantity_TOC_RGB ) : Quantity_Color( 85 / 255., 85 / 255., 255 / 255., Quantity_TOC_RGB );
865       ic->SetColor( myPreviewPlane, c , false );
866       ic->Display( myPreviewPlane, 1, 0, false );
867       myPreviewPlaneVector.push_back( myPreviewPlane );
868     }
869   }
870   myModel->update();
871
872   double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
873   getMinMaxFromContext( ic, myModel->trihedronSize(), aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
874   gp_Pnt aRotationCenter( (aXmax + aXmin) * 0.5,
875                           (aYmax + aYmin) * 0.5,
876                           (aZmax + aZmin) * 0.5 );
877   Bnd_Box aMinMax;
878   aMinMax.Update( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax );
879
880   myInteractor->setPlanes( myPreviewPlaneVector );
881   myInteractor->setRotationCenter( aRotationCenter );
882   myInteractor->setMinMax( aMinMax );
883   myInteractor->setEnabled( true );
884 }
885
886 void OCCViewer_ClippingDlg::updatePreview() {
887   int aCurPlaneIndex = ComboBoxPlanes->currentIndex();
888   int count = clipPlanesCount();
889   if ( myBusy || 
890        !isValid() || 
891        myIsPlaneCreation ||
892        !myModel || 
893        count == 0 || 
894        (aCurPlaneIndex +1 > count) ||
895        !PreviewCheckBox->isChecked())
896     return;
897   
898   Handle(AIS_InteractiveContext) ic = myModel->getAISContext();
899   
900   OCCViewer_ClipPlane& aClipPlane = getClipPlane(aCurPlaneIndex);
901   Handle(AIS_Plane) myPreviewPlane;
902
903   if (aClipPlane.IsOn) {
904     double aSize;
905     gp_Pnt aBasePnt;
906     gp_Dir aNormal;
907     clipPlaneParams(aClipPlane, ic, aSize, aBasePnt, aNormal, myModel->trihedronSize());
908     if(myPreviewPlaneVector.size() < clipPlanesCount()) {
909       myPreviewPlaneVector.resize(clipPlanesCount());
910     }
911     myPreviewPlane = myPreviewPlaneVector[aCurPlaneIndex];
912     if(myPreviewPlane.IsNull()) {
913       //Plane was not created
914       myPreviewPlane = new AIS_Plane( new Geom_Plane( aBasePnt, aNormal ), aBasePnt );
915       myPreviewPlane->SetTypeOfSensitivity( Select3D_TOS_INTERIOR );
916       myPreviewPlane->SetSize( aSize, aSize );
917       ic->Display( myPreviewPlane, 1, 0, false );
918       ic->SetWidth( myPreviewPlane, 10, false );
919       ic->SetMaterial( myPreviewPlane, Graphic3d_NOM_PLASTIC, false );
920       ic->SetTransparency( myPreviewPlane, 0.5, false );
921       myPreviewPlaneVector[aCurPlaneIndex] = myPreviewPlane;
922     } else {      
923       myPreviewPlane->SetComponent( new Geom_Plane( aBasePnt, aNormal ) );
924       myPreviewPlane->SetCenter( aBasePnt );
925       myPreviewPlane->SetSize( aSize, aSize );  
926     }
927
928     ic->SetColor( myPreviewPlane, Quantity_Color( 255. / 255., 70. / 255., 0. / 255., Quantity_TOC_RGB ), false );
929     ic->Update( myPreviewPlane, Standard_False );
930   } else {
931     if(myPreviewPlaneVector.size() > aCurPlaneIndex ) {
932       myPreviewPlane = myPreviewPlaneVector[aCurPlaneIndex];
933       if(ic->IsDisplayed(myPreviewPlane)) {
934         ic->Erase( myPreviewPlane, false );
935         ic->Remove( myPreviewPlane, false );
936       }
937       myPreviewPlaneVector[aCurPlaneIndex].Nullify();
938     }
939   }
940   for(int i = 0; i < myPreviewPlaneVector.size(); i++) {
941     if( i == aCurPlaneIndex ) continue;
942     if(!myPreviewPlaneVector[i].IsNull())
943       ic->SetColor( myPreviewPlaneVector[i], Quantity_Color( 85 / 255., 85 / 255., 255 / 255., Quantity_TOC_RGB ), false );
944   }
945   myModel->update();
946
947   double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
948   getMinMaxFromContext( ic, myModel->trihedronSize(), aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
949   gp_Pnt aRotationCenter( (aXmax + aXmin) * 0.5,
950                           (aYmax + aYmin) * 0.5,
951                           (aZmax + aZmin) * 0.5 );
952   Bnd_Box aMinMax;
953   aMinMax.Update( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax );
954
955   myInteractor->setPlanes( myPreviewPlaneVector );
956   myInteractor->setRotationCenter( aRotationCenter );
957   myInteractor->setMinMax( aMinMax );
958 }
959
960 /*!
961   Erases preview of clipping plane
962 */
963 void OCCViewer_ClippingDlg::erasePreview()
964 {
965   if ( !myModel )
966     return;
967
968   Handle(AIS_InteractiveContext) ic = myModel->getAISContext();
969
970   for ( int i=0; i < myPreviewPlaneVector.size(); i++ ) {
971   Handle(AIS_Plane) myPreviewPlane = myPreviewPlaneVector[i];
972     if ( !myPreviewPlane.IsNull() && ic->IsDisplayed( myPreviewPlane ) ) {
973       ic->Erase( myPreviewPlane, false );
974       ic->Remove( myPreviewPlane, false );
975       myPreviewPlane.Nullify();
976     }
977   }
978   myPreviewPlaneVector.clear();
979   myModel->update();
980   myInteractor->setEnabled( false );
981 }
982
983 /*!
984   Return true if plane parameters are valid
985 */
986 bool OCCViewer_ClippingDlg::isValid()
987 {
988   return ( SpinBox_Dx->value() !=0 || SpinBox_Dy->value() !=0 || SpinBox_Dz->value() !=0 );
989 }
990
991 /*!
992   Update view after changes
993 */
994 void OCCViewer_ClippingDlg::updateClipping()
995 {
996   if (PreviewCheckBox->isChecked() || AutoApplyCheckBox->isChecked())
997   {
998     if (AutoApplyCheckBox->isChecked()) {
999       onApply();
1000     }
1001     
1002     if (!PreviewCheckBox->isChecked())
1003       myModel->update();
1004     else 
1005       updatePreview();
1006   }
1007 }
1008
1009 /*!
1010   Updates state of user controls.
1011 */
1012 void OCCViewer_ClippingDlg::updateControls()
1013 {
1014   if ( clipPlanesCount() == 0 )
1015   {
1016     initParam();
1017     return;
1018   }
1019
1020   int aPlaneIdx = ComboBoxPlanes->currentIndex();
1021
1022   OCCViewer_ClipPlane& aPlane = getClipPlane( aPlaneIdx );
1023
1024   double aPlaneDx  = 0.0;
1025   double aPlaneDy  = 0.0;
1026   double aPlaneDz  = 0.0;
1027   double aDistance = 0.0;
1028   aPlane.OrientationToXYZ( aPlaneDx, aPlaneDy, aPlaneDz );
1029
1030   if ( aPlane.Mode == OCCViewer_ClipPlane::Absolute )
1031   {
1032     ModeStackedLayout->setCurrentIndex( 0 );
1033
1034     // Set plane parameters in the dialog
1035     SpinBox_X->setValue( aPlane.X );
1036     SpinBox_Y->setValue( aPlane.Y );
1037     SpinBox_Z->setValue( aPlane.Z );
1038     SpinBox_Dx->setValue( aPlaneDx );
1039     SpinBox_Dy->setValue( aPlaneDy );
1040     SpinBox_Dz->setValue( aPlaneDz );
1041     CBAbsoluteOrientation->setCurrentIndex( aPlane.OrientationType );
1042     onOrientationAbsoluteChanged( aPlane.OrientationType );
1043   }
1044   else if( aPlane.Mode == OCCViewer_ClipPlane::Relative )
1045   {
1046     ModeStackedLayout->setCurrentIndex( 1 );
1047
1048     // Set plane parameters in the dialog
1049     SpinSliderRotation1->setValue( int( aPlane.RelativeOrientation.Rotation1 ) );
1050     SpinSliderRotation2->setValue( int( aPlane.RelativeOrientation.Rotation2 ) );
1051
1052     XYZToDistance( myModel->getAISContext(),
1053                    myModel->trihedronSize(),
1054                    aPlane.X, aPlane.Y, aPlane.Z,
1055                    aPlaneDx, aPlaneDy, aPlaneDz,
1056                    aDistance );
1057
1058     SpinSliderDistance->setValue( aDistance );
1059
1060     CBRelativeOrientation->setCurrentIndex( aPlane.OrientationType );
1061     onOrientationRelativeChanged( aPlane.OrientationType );
1062   }
1063
1064   isActivePlane->setChecked( aPlane.IsOn );
1065 }
1066
1067 /*!
1068   SLOT on new button click: create a new clipping plane
1069 */
1070 void OCCViewer_ClippingDlg::ClickOnNew()
1071 {
1072   OCCViewer_ClipPlane aClipPlane;
1073
1074   // init controls state
1075   myIsUpdatingControls = true;
1076   initParam();
1077   myIsUpdatingControls = false;
1078
1079   // init plane according to the state of controls
1080   setPlaneParam( aClipPlane );
1081
1082   // add plane
1083   myLocalPlanes.push_back( aClipPlane );
1084   synchronize();
1085 }
1086
1087 /*!
1088   SLOT on delete button click: Delete selected clipping plane
1089 */
1090 void OCCViewer_ClippingDlg::ClickOnDelete()
1091 {
1092   int aPlaneIndex = ComboBoxPlanes->currentIndex();
1093   if ( (clipPlanesCount() == 0) || (aPlaneIndex+1 > clipPlanesCount()))
1094     return;
1095
1096   myLocalPlanes.erase(myLocalPlanes.begin() + aPlaneIndex);
1097
1098   Handle(AIS_InteractiveContext) ic = myModel->getAISContext();
1099
1100   if(aPlaneIndex+1 <= myPreviewPlaneVector.size()) {
1101     Handle(AIS_Plane) myPreviewPlane = myPreviewPlaneVector[aPlaneIndex];
1102     if ( !myPreviewPlane.IsNull() && ic->IsDisplayed( myPreviewPlane ) ) {
1103       ic->Erase( myPreviewPlane, false );
1104       ic->Remove( myPreviewPlane, false );
1105     }
1106     myPreviewPlaneVector.erase(myPreviewPlaneVector.begin() + aPlaneIndex);
1107   }
1108   synchronize();
1109   if (AutoApplyCheckBox->isChecked()) {
1110     onApply();
1111   }
1112   myModel->update();
1113 }
1114
1115 /*!
1116   SLOT on disable all button click: Restore initial state of viewer,
1117   erase all clipping planes
1118 */
1119 void OCCViewer_ClippingDlg::ClickOnDisableAll()
1120 {
1121   AutoApplyCheckBox->setChecked (false);
1122   int aClipPlanesCount = clipPlanesCount();
1123   for ( int anIndex = 0; anIndex < aClipPlanesCount; anIndex++)
1124   {
1125     OCCViewer_ClipPlane& aPlane = getClipPlane(anIndex);
1126     aPlane.IsOn = false;
1127   }
1128   erasePreview();
1129   isActivePlane->setChecked(false);
1130   myModel->setClipPlanes(myLocalPlanes);
1131   myModel->update();
1132 }
1133
1134 /*!
1135   SLOT on ok button click: sets cutting plane and closes dialog
1136 */
1137 void OCCViewer_ClippingDlg::ClickOnOk()
1138 {
1139   onApply();
1140   ClickOnClose();
1141 }
1142
1143 /*!
1144   SLOT on Apply button click: sets cutting plane and update viewer
1145 */
1146 void OCCViewer_ClippingDlg::ClickOnApply()
1147 {
1148   onApply();
1149   myModel->update();
1150 }
1151
1152 /*!
1153   SLOT on close button click: erases preview and rejects dialog
1154 */
1155 void OCCViewer_ClippingDlg::ClickOnClose()
1156 {
1157   erasePreview();
1158   OCCViewer_ViewWindow* v = qobject_cast<OCCViewer_ViewWindow*>(parent());
1159   if(v)
1160     v->onClipping(false);
1161 }
1162
1163 /*!
1164   SLOT on help button click: opens a help page
1165 */
1166 void OCCViewer_ClippingDlg::ClickOnHelp()
1167 {
1168   SUIT_Application* app = SUIT_Session::session()->activeApplication();
1169   if ( app )
1170     app->onHelpContextModule( "GUI", "occ_3d_viewer_page.html", "clipping_planes" );
1171 }
1172
1173 /*!
1174   Set absolute mode of clipping plane
1175 */
1176 void OCCViewer_ClippingDlg::onModeAbsolute()
1177 {
1178   myIsPlaneCreation = true;
1179   ModeStackedLayout->setCurrentIndex(0);
1180   ClickOnNew();
1181   myIsPlaneCreation = false;
1182   updateClipping();
1183 }
1184
1185 /*!
1186   Set relative mode of clipping plane
1187 */
1188 void OCCViewer_ClippingDlg::onModeRelative()
1189 {
1190   myIsPlaneCreation = true;
1191   ModeStackedLayout->setCurrentIndex(1);
1192   ClickOnNew();
1193   myIsPlaneCreation = false;
1194   SetCurrentPlaneParam();
1195   updateClipping();
1196 }
1197
1198 /*!
1199   SLOT: called on value of clipping plane changed
1200 */
1201 void OCCViewer_ClippingDlg::onValueChanged()
1202 {
1203   if ( myIsUpdatingControls )
1204   {
1205     return;
1206   }
1207
1208   SetCurrentPlaneParam();
1209
1210   if ( myIsSelectPlane )
1211   {
1212     return;
1213   }
1214
1215   updateClipping();
1216 }
1217
1218 /*!
1219   Set current parameters of selected plane
1220 */
1221 void OCCViewer_ClippingDlg::onSelectPlane ( int theIndex )
1222 {
1223   if ( clipPlanesCount() == 0 )
1224   {
1225     return;
1226   }
1227
1228   OCCViewer_ClipPlane& aClipPlane = getClipPlane( theIndex );
1229
1230   myIsSelectPlane = true;
1231   updateControls();
1232   ComboBoxPlanes->setCurrentIndex( theIndex );
1233   myIsSelectPlane = false;
1234 }
1235
1236 /*!
1237   Restore parameters of selected plane
1238 */
1239 void OCCViewer_ClippingDlg::SetCurrentPlaneParam()
1240 {
1241   if ( clipPlanesCount() == 0 || myIsSelectPlane || myBusy )
1242   {
1243     return;
1244   }
1245
1246   int aCurPlaneIndex = ComboBoxPlanes->currentIndex();
1247
1248   OCCViewer_ClipPlane& aPlane = getClipPlane( aCurPlaneIndex );
1249
1250   setPlaneParam( aPlane );
1251 }
1252
1253 /*!
1254   SLOT on reset button click: sets default values
1255 */
1256 void OCCViewer_ClippingDlg::onReset()
1257 {
1258   myBusy = true;
1259   SpinBox_X->setValue(0);
1260   SpinBox_Y->setValue(0);
1261   SpinBox_Z->setValue(0);
1262   myBusy = false;
1263
1264   updateClipping();
1265 }
1266
1267 /*!
1268   SLOT on invert button click: inverts normal of cutting plane
1269 */
1270 void OCCViewer_ClippingDlg::onInvert()
1271 {
1272   double Dx = SpinBox_Dx->value();
1273   double Dy = SpinBox_Dy->value();
1274   double Dz = SpinBox_Dz->value();
1275
1276   myBusy = true;
1277   SpinBox_Dx->setValue( -Dx );
1278   SpinBox_Dy->setValue( -Dy );
1279   SpinBox_Dz->setValue( -Dz );
1280   myBusy = false;
1281
1282   if ( clipPlanesCount() != 0 )
1283   {
1284     int aCurPlaneIndex = ComboBoxPlanes->currentIndex();
1285     OCCViewer_ClipPlane& aPlane = getClipPlane( aCurPlaneIndex );
1286     aPlane.AbsoluteOrientation.IsInvert = !aPlane.AbsoluteOrientation.IsInvert;
1287   }
1288   updateClipping();
1289 }
1290
1291 /*!
1292   SLOT: called on orientation of clipping plane in absolute mode changed
1293 */
1294 void OCCViewer_ClippingDlg::onOrientationAbsoluteChanged( int mode )
1295 {
1296   bool isUserMode = (mode==0);
1297
1298   TextLabelX->setEnabled( isUserMode );
1299   TextLabelY->setEnabled( isUserMode );
1300   TextLabelZ->setEnabled( isUserMode );
1301
1302   SpinBox_X->setEnabled( isUserMode );
1303   SpinBox_Y->setEnabled( isUserMode );
1304   SpinBox_Z->setEnabled( isUserMode );
1305
1306   TextLabelDx->setEnabled( isUserMode );
1307   TextLabelDy->setEnabled( isUserMode );
1308   TextLabelDz->setEnabled( isUserMode );
1309
1310   SpinBox_Dx->setEnabled( isUserMode );
1311   SpinBox_Dy->setEnabled( isUserMode );
1312   SpinBox_Dz->setEnabled( isUserMode );
1313
1314   if ( !isUserMode ) {
1315
1316     double aDx = 0, aDy = 0, aDz = 0;
1317
1318     if ( mode == 1 )
1319     {
1320       aDz = 1;
1321       TextLabelZ->setEnabled( true );
1322       SpinBox_Z->setEnabled( true );
1323       SpinBox_Z->setFocus();
1324     }
1325     else if ( mode == 2 )
1326     {
1327       aDx = 1;
1328       TextLabelX->setEnabled( true );
1329       SpinBox_X->setEnabled( true );
1330       SpinBox_X->setFocus();
1331     }
1332     else if ( mode == 3 )
1333     {
1334       aDy = 1;
1335       TextLabelY->setEnabled( true );
1336       SpinBox_Y->setEnabled( true );
1337       SpinBox_Y->setFocus();
1338     }
1339     
1340     int aCurPlaneIndex = ComboBoxPlanes->currentIndex();
1341     OCCViewer_ClipPlane& aPlane = getClipPlane( aCurPlaneIndex );
1342     if ( aPlane.AbsoluteOrientation.IsInvert == true )
1343     {
1344       aDx = -aDx;
1345       aDy = -aDy;
1346       aDz = -aDz;
1347     }
1348     
1349     myBusy = true;
1350     SpinBox_Dx->setValue( aDx );
1351     SpinBox_Dy->setValue( aDy );
1352     SpinBox_Dz->setValue( aDz );
1353     myBusy = false;
1354   }
1355
1356   if ( !myIsUpdatingControls )
1357   {
1358     SetCurrentPlaneParam();
1359     updateClipping();
1360   }
1361 }
1362
1363 /*!
1364   SLOT: called on orientation of clipping plane in relative mode changed
1365 */
1366 void OCCViewer_ClippingDlg::onOrientationRelativeChanged (int theItem)
1367 {
1368   if ( clipPlanesCount() == 0 )
1369     return;
1370   
1371   if ( theItem == 0 ) {
1372     TextLabelRotation1->setText( tr( "ROTATION_AROUND_X_Y2Z" ) );
1373     TextLabelRotation2->setText( tr( "ROTATION_AROUND_Y_X2Z" ) );
1374   }
1375   else if ( theItem == 1 ) {
1376     TextLabelRotation1->setText( tr( "ROTATION_AROUND_Y_Z2X" ) );
1377     TextLabelRotation2->setText( tr( "ROTATION_AROUND_Z_Y2X" ) );
1378   }
1379   else if ( theItem == 2 ) {
1380     TextLabelRotation1->setText( tr( "ROTATION_AROUND_Z_X2Y" ) );
1381     TextLabelRotation2->setText( tr( "ROTATION_AROUND_X_Z2Y" ) );
1382   }
1383
1384   if ( !myIsUpdatingControls )
1385   {
1386     if( (QComboBox*)sender() == CBRelativeOrientation )
1387     {
1388       SetCurrentPlaneParam();
1389     }
1390
1391     updateClipping();
1392   }
1393 }
1394
1395 /*!
1396   SLOT: called on preview check box toggled
1397 */
1398 void OCCViewer_ClippingDlg::onPreview( bool on )
1399 {
1400   erasePreview();
1401   if ( on ) 
1402     displayPreview();
1403 }
1404
1405 /*!
1406   SLOT: called on Auto Apply check box toggled
1407 */
1408 void OCCViewer_ClippingDlg::onAutoApply( bool toggled )
1409 {
1410   if ( toggled ) {
1411     onApply();
1412     myModel->update();
1413   }  
1414 }
1415
1416 /*!
1417   SLOT on Apply button click: sets cutting plane
1418 */
1419 void OCCViewer_ClippingDlg::onApply()
1420 {
1421   if ( myBusy )
1422     return;
1423   myIsSelectPlane = true;
1424
1425   qApp->processEvents();
1426   QApplication::setOverrideCursor( Qt::WaitCursor );
1427   qApp->processEvents();
1428
1429   myModel->setClipPlanes(myLocalPlanes);
1430
1431   QApplication::restoreOverrideCursor();
1432   myIsSelectPlane = false;
1433 }
1434
1435 /*!
1436   SLOT: Called when clip plane is clicked in viewer.
1437 */
1438 void OCCViewer_ClippingDlg::onPlaneClicked( const Handle(AIS_Plane)& thePlane )
1439 {
1440   for ( int aPlaneIt = 0; aPlaneIt < myPreviewPlaneVector.size(); aPlaneIt++ )
1441   {
1442     Handle(AIS_Plane)& aPlane = myPreviewPlaneVector.at( aPlaneIt );
1443     if ( aPlane != thePlane )
1444     {
1445       continue;
1446     }
1447
1448     ComboBoxPlanes->setCurrentIndex( aPlaneIt );
1449
1450     break;
1451   }
1452 }
1453
1454 /*!
1455   SLOT: Called when clip plane is changed by dragging in viewer.
1456 */
1457 void OCCViewer_ClippingDlg::onPlaneDragged( const Handle(AIS_Plane)& thePlane )
1458 {
1459   for ( int aPlaneIt = 0; aPlaneIt < myPreviewPlaneVector.size(); aPlaneIt++ )
1460   {
1461     Handle(AIS_Plane)& aPlane = myPreviewPlaneVector.at( aPlaneIt );
1462     if ( aPlane != thePlane )
1463     {
1464       continue;
1465     }
1466
1467     OCCViewer_ClipPlane& aClipPlane = getClipPlane( aPlaneIt );
1468
1469     gp_Pln aPln = thePlane->Component()->Pln();
1470     const gp_Pnt& aPlaneP = aPln.Location();
1471     const gp_Dir& aPlaneN = aPln.Axis().Direction();
1472
1473     aClipPlane.X  = aPlaneP.X();
1474     aClipPlane.Y  = aPlaneP.Y();
1475     aClipPlane.Z  = aPlaneP.Z();
1476
1477     if ( aClipPlane.Mode == OCCViewer_ClipPlane::Absolute )
1478     {
1479       if ( aClipPlane.OrientationType == OCCViewer_ClipPlane::AbsoluteCustom )
1480       {
1481         aClipPlane.AbsoluteOrientation.Dx = aPlaneN.X();
1482         aClipPlane.AbsoluteOrientation.Dy = aPlaneN.Y();
1483         aClipPlane.AbsoluteOrientation.Dz = aPlaneN.Z();
1484       }
1485     }
1486     else
1487     {
1488       OCCViewer_ClipPlane::DXYZToRelative( aPlaneN.X(), aPlaneN.Y(), aPlaneN.Z(),
1489                                            aClipPlane.OrientationType,
1490                                            aClipPlane.RelativeOrientation.Rotation1,
1491                                            aClipPlane.RelativeOrientation.Rotation2 );
1492     }
1493
1494     myIsUpdatingControls = true;
1495     updateControls();
1496     myIsUpdatingControls = false;
1497
1498     if ( AutoApplyCheckBox->isChecked() )
1499     {
1500       onApply();
1501     }
1502
1503     break;
1504   }
1505 }
1506
1507 OCCViewer_ClipPlane& OCCViewer_ClippingDlg::getClipPlane( int theIdx )
1508 {
1509   return myLocalPlanes[theIdx];
1510 }
1511
1512 int OCCViewer_ClippingDlg::clipPlanesCount()
1513 {
1514   return myLocalPlanes.size();
1515 }
1516
1517 OCCViewer_ClipPlane::PlaneMode OCCViewer_ClippingDlg::currentPlaneMode() const
1518 {
1519   return ModeStackedLayout->currentIndex() == 0
1520     ? OCCViewer_ClipPlane::Absolute 
1521     : OCCViewer_ClipPlane::Relative;
1522 }