Salome HOME
INT PAL 0052613: Creation of clipping plane with absolute mode is incorrect
[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       thePlane.AbsoluteOrientation.IsInvert = false;
748     }
749     else
750     {
751       thePlane.AbsoluteOrientation.IsInvert = SpinBox_Dx->value() < 0.0
752                                            || SpinBox_Dy->value() < 0.0
753                                            || SpinBox_Dz->value() < 0.0;
754     }
755
756     thePlane.X = SpinBox_X->value();
757     thePlane.Y = SpinBox_Y->value();
758     thePlane.Z = SpinBox_Z->value();
759   }
760   else
761   {
762     thePlane.RelativeOrientation.Rotation1 = SpinSliderRotation1->value();
763     thePlane.RelativeOrientation.Rotation2 = SpinSliderRotation2->value();
764
765     double aPlaneDx = 0.0;
766     double aPlaneDy = 0.0;
767     double aPlaneDz = 0.0;
768     double aX = 0.0;
769     double aY = 0.0;
770     double aZ = 0.0;
771
772     OCCViewer_ClipPlane::RelativeToDXYZ( thePlane.OrientationType,
773                                          thePlane.RelativeOrientation.Rotation1,
774                                          thePlane.RelativeOrientation.Rotation2,
775                                          aPlaneDx, aPlaneDy, aPlaneDz );
776
777     DistanceToXYZ( myModel->getAISContext(),
778                    myModel->trihedronSize(),
779                    SpinSliderDistance->value(),
780                    aPlaneDx, aPlaneDy, aPlaneDz,
781                    aX, aY, aZ );
782
783     thePlane.X = aX;
784     thePlane.Y = aY;
785     thePlane.Z = aZ;
786   }
787
788   thePlane.IsOn = isActivePlane->isChecked();
789 }
790
791 /*!
792   Synchronize dialog's widgets with data
793 */
794 void OCCViewer_ClippingDlg::synchronize()
795 {
796   ComboBoxPlanes->clear();
797   int aNbPlanesAbsolute = myLocalPlanes.size();
798
799   QString aName;
800   for(int i = 1; i<=aNbPlanesAbsolute; i++ ) {
801     aName = QString("Plane %1").arg(i);
802     ComboBoxPlanes->addItem( aName );
803   }
804
805   int aPos = ComboBoxPlanes->count() - 1;
806   ComboBoxPlanes->setCurrentIndex( aPos );
807
808   bool anIsControlsEnable = ( aPos >= 0 );
809   if ( anIsControlsEnable ) {
810     onSelectPlane( aPos );
811   }
812   else {
813     ComboBoxPlanes->addItem( tr( "NO_PLANES" ) );
814     initParam();
815   }
816   if ( currentPlaneMode() == OCCViewer_ClipPlane::Absolute )
817   {
818     SpinBox_X->setEnabled( anIsControlsEnable );
819     SpinBox_Y->setEnabled( anIsControlsEnable );
820     SpinBox_Z->setEnabled( anIsControlsEnable );
821     SpinBox_Dx->setEnabled( anIsControlsEnable );
822     SpinBox_Dy->setEnabled( anIsControlsEnable );
823     SpinBox_Dz->setEnabled( anIsControlsEnable );
824     CBAbsoluteOrientation->setEnabled( anIsControlsEnable );
825     invertButton->setEnabled( anIsControlsEnable );
826     resetButton->setEnabled( anIsControlsEnable );
827   }
828   else if ( currentPlaneMode() == OCCViewer_ClipPlane::Relative )
829   {
830     CBRelativeOrientation->setEnabled( anIsControlsEnable );
831     SpinSliderDistance->setEnabled( anIsControlsEnable );
832     SpinSliderRotation1->setEnabled( anIsControlsEnable );
833     SpinSliderRotation2->setEnabled( anIsControlsEnable );
834     isActivePlane->setEnabled( anIsControlsEnable );
835   }
836   isActivePlane->setEnabled( anIsControlsEnable );
837 }
838
839 /*!
840   Displays preview of clipping plane
841 */
842 void OCCViewer_ClippingDlg::displayPreview()
843 {
844   if ( myBusy || !isValid() || !myModel)
845     return;
846
847   Handle(AIS_InteractiveContext) ic = myModel->getAISContext();
848   
849   int aCurPlaneIndex = ComboBoxPlanes->currentIndex();
850
851   for ( int i=0; i < clipPlanesCount(); i++ ) {
852     OCCViewer_ClipPlane& aClipPlane = getClipPlane(i);
853     if ( aClipPlane.IsOn ) {
854       Handle(AIS_Plane) myPreviewPlane;
855       double aSize;
856       gp_Pnt aBasePnt;
857       gp_Dir aNormal;
858       clipPlaneParams(aClipPlane, ic, aSize, aBasePnt, aNormal, myModel->trihedronSize());
859       myPreviewPlane = new AIS_Plane( new Geom_Plane( aBasePnt, aNormal ), aBasePnt );
860       myPreviewPlane->SetTypeOfSensitivity( Select3D_TOS_INTERIOR );
861       myPreviewPlane->SetSize( aSize, aSize );
862       ic->SetWidth( myPreviewPlane, 10, false );
863       ic->SetMaterial( myPreviewPlane, Graphic3d_NOM_PLASTIC, false );
864       ic->SetTransparency( myPreviewPlane, 0.5, false );
865       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 );
866       ic->SetColor( myPreviewPlane, c , false );
867       ic->Display( myPreviewPlane, 1, 0, false );
868       myPreviewPlaneVector.push_back( myPreviewPlane );
869     }
870   }
871   myModel->update();
872
873   double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
874   getMinMaxFromContext( ic, myModel->trihedronSize(), aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
875   gp_Pnt aRotationCenter( (aXmax + aXmin) * 0.5,
876                           (aYmax + aYmin) * 0.5,
877                           (aZmax + aZmin) * 0.5 );
878   Bnd_Box aMinMax;
879   aMinMax.Update( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax );
880
881   myInteractor->setPlanes( myPreviewPlaneVector );
882   myInteractor->setRotationCenter( aRotationCenter );
883   myInteractor->setMinMax( aMinMax );
884   myInteractor->setEnabled( true );
885 }
886
887 void OCCViewer_ClippingDlg::updatePreview() {
888   int aCurPlaneIndex = ComboBoxPlanes->currentIndex();
889   int count = clipPlanesCount();
890   if ( myBusy || 
891        !isValid() || 
892        myIsPlaneCreation ||
893        !myModel || 
894        count == 0 || 
895        (aCurPlaneIndex +1 > count) ||
896        !PreviewCheckBox->isChecked())
897     return;
898   
899   Handle(AIS_InteractiveContext) ic = myModel->getAISContext();
900   
901   OCCViewer_ClipPlane& aClipPlane = getClipPlane(aCurPlaneIndex);
902   Handle(AIS_Plane) myPreviewPlane;
903
904   if (aClipPlane.IsOn) {
905     double aSize;
906     gp_Pnt aBasePnt;
907     gp_Dir aNormal;
908     clipPlaneParams(aClipPlane, ic, aSize, aBasePnt, aNormal, myModel->trihedronSize());
909     if(myPreviewPlaneVector.size() < clipPlanesCount()) {
910       myPreviewPlaneVector.resize(clipPlanesCount());
911     }
912     myPreviewPlane = myPreviewPlaneVector[aCurPlaneIndex];
913     if(myPreviewPlane.IsNull()) {
914       //Plane was not created
915       myPreviewPlane = new AIS_Plane( new Geom_Plane( aBasePnt, aNormal ), aBasePnt );
916       myPreviewPlane->SetTypeOfSensitivity( Select3D_TOS_INTERIOR );
917       myPreviewPlane->SetSize( aSize, aSize );
918       ic->Display( myPreviewPlane, 1, 0, false );
919       ic->SetWidth( myPreviewPlane, 10, false );
920       ic->SetMaterial( myPreviewPlane, Graphic3d_NOM_PLASTIC, false );
921       ic->SetTransparency( myPreviewPlane, 0.5, false );
922       myPreviewPlaneVector[aCurPlaneIndex] = myPreviewPlane;
923     } else {      
924       myPreviewPlane->SetComponent( new Geom_Plane( aBasePnt, aNormal ) );
925       myPreviewPlane->SetCenter( aBasePnt );
926       myPreviewPlane->SetSize( aSize, aSize );  
927     }
928
929     ic->SetColor( myPreviewPlane, Quantity_Color( 255. / 255., 70. / 255., 0. / 255., Quantity_TOC_RGB ), false );
930     ic->Update( myPreviewPlane, Standard_False );
931   } else {
932     if(myPreviewPlaneVector.size() > aCurPlaneIndex ) {
933       myPreviewPlane = myPreviewPlaneVector[aCurPlaneIndex];
934       if(ic->IsDisplayed(myPreviewPlane)) {
935         ic->Erase( myPreviewPlane, false );
936         ic->Remove( myPreviewPlane, false );
937       }
938       myPreviewPlaneVector[aCurPlaneIndex].Nullify();
939     }
940   }
941   for(int i = 0; i < myPreviewPlaneVector.size(); i++) {
942     if( i == aCurPlaneIndex ) continue;
943     if(!myPreviewPlaneVector[i].IsNull())
944       ic->SetColor( myPreviewPlaneVector[i], Quantity_Color( 85 / 255., 85 / 255., 255 / 255., Quantity_TOC_RGB ), false );
945   }
946   myModel->update();
947
948   double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
949   getMinMaxFromContext( ic, myModel->trihedronSize(), aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
950   gp_Pnt aRotationCenter( (aXmax + aXmin) * 0.5,
951                           (aYmax + aYmin) * 0.5,
952                           (aZmax + aZmin) * 0.5 );
953   Bnd_Box aMinMax;
954   aMinMax.Update( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax );
955
956   myInteractor->setPlanes( myPreviewPlaneVector );
957   myInteractor->setRotationCenter( aRotationCenter );
958   myInteractor->setMinMax( aMinMax );
959 }
960
961 /*!
962   Erases preview of clipping plane
963 */
964 void OCCViewer_ClippingDlg::erasePreview()
965 {
966   if ( !myModel )
967     return;
968
969   Handle(AIS_InteractiveContext) ic = myModel->getAISContext();
970
971   for ( int i=0; i < myPreviewPlaneVector.size(); i++ ) {
972   Handle(AIS_Plane) myPreviewPlane = myPreviewPlaneVector[i];
973     if ( !myPreviewPlane.IsNull() && ic->IsDisplayed( myPreviewPlane ) ) {
974       ic->Erase( myPreviewPlane, false );
975       ic->Remove( myPreviewPlane, false );
976       myPreviewPlane.Nullify();
977     }
978   }
979   myPreviewPlaneVector.clear();
980   myModel->update();
981   myInteractor->setEnabled( false );
982 }
983
984 /*!
985   Return true if plane parameters are valid
986 */
987 bool OCCViewer_ClippingDlg::isValid()
988 {
989   return ( SpinBox_Dx->value() !=0 || SpinBox_Dy->value() !=0 || SpinBox_Dz->value() !=0 );
990 }
991
992 /*!
993   Update view after changes
994 */
995 void OCCViewer_ClippingDlg::updateClipping()
996 {
997   if (PreviewCheckBox->isChecked() || AutoApplyCheckBox->isChecked())
998   {
999     if (AutoApplyCheckBox->isChecked()) {
1000       onApply();
1001     }
1002     
1003     if (!PreviewCheckBox->isChecked())
1004       myModel->update();
1005     else 
1006       updatePreview();
1007   }
1008 }
1009
1010 /*!
1011   Updates state of user controls.
1012 */
1013 void OCCViewer_ClippingDlg::updateControls()
1014 {
1015   if ( clipPlanesCount() == 0 )
1016   {
1017     initParam();
1018     return;
1019   }
1020
1021   int aPlaneIdx = ComboBoxPlanes->currentIndex();
1022
1023   OCCViewer_ClipPlane& aPlane = getClipPlane( aPlaneIdx );
1024
1025   double aPlaneDx  = 0.0;
1026   double aPlaneDy  = 0.0;
1027   double aPlaneDz  = 0.0;
1028   double aDistance = 0.0;
1029   aPlane.OrientationToXYZ( aPlaneDx, aPlaneDy, aPlaneDz );
1030
1031   if ( aPlane.Mode == OCCViewer_ClipPlane::Absolute )
1032   {
1033     ModeStackedLayout->setCurrentIndex( 0 );
1034
1035     // Set plane parameters in the dialog
1036     SpinBox_X->setValue( aPlane.X );
1037     SpinBox_Y->setValue( aPlane.Y );
1038     SpinBox_Z->setValue( aPlane.Z );
1039     SpinBox_Dx->setValue( aPlaneDx );
1040     SpinBox_Dy->setValue( aPlaneDy );
1041     SpinBox_Dz->setValue( aPlaneDz );
1042     CBAbsoluteOrientation->setCurrentIndex( aPlane.OrientationType );
1043     onOrientationAbsoluteChanged( aPlane.OrientationType );
1044   }
1045   else if( aPlane.Mode == OCCViewer_ClipPlane::Relative )
1046   {
1047     ModeStackedLayout->setCurrentIndex( 1 );
1048
1049     // Set plane parameters in the dialog
1050     SpinSliderRotation1->setValue( int( aPlane.RelativeOrientation.Rotation1 ) );
1051     SpinSliderRotation2->setValue( int( aPlane.RelativeOrientation.Rotation2 ) );
1052
1053     XYZToDistance( myModel->getAISContext(),
1054                    myModel->trihedronSize(),
1055                    aPlane.X, aPlane.Y, aPlane.Z,
1056                    aPlaneDx, aPlaneDy, aPlaneDz,
1057                    aDistance );
1058
1059     SpinSliderDistance->setValue( aDistance );
1060
1061     CBRelativeOrientation->setCurrentIndex( aPlane.OrientationType );
1062     onOrientationRelativeChanged( aPlane.OrientationType );
1063   }
1064
1065   isActivePlane->setChecked( aPlane.IsOn );
1066 }
1067
1068 /*!
1069   SLOT on new button click: create a new clipping plane
1070 */
1071 void OCCViewer_ClippingDlg::ClickOnNew()
1072 {
1073   OCCViewer_ClipPlane aClipPlane;
1074
1075   // init controls state
1076   myIsUpdatingControls = true;
1077   initParam();
1078   myIsUpdatingControls = false;
1079
1080   // init plane according to the state of controls
1081   setPlaneParam( aClipPlane );
1082
1083   // add plane
1084   myLocalPlanes.push_back( aClipPlane );
1085   synchronize();
1086 }
1087
1088 /*!
1089   SLOT on delete button click: Delete selected clipping plane
1090 */
1091 void OCCViewer_ClippingDlg::ClickOnDelete()
1092 {
1093   int aPlaneIndex = ComboBoxPlanes->currentIndex();
1094   if ( (clipPlanesCount() == 0) || (aPlaneIndex+1 > clipPlanesCount()))
1095     return;
1096
1097   myLocalPlanes.erase(myLocalPlanes.begin() + aPlaneIndex);
1098
1099   Handle(AIS_InteractiveContext) ic = myModel->getAISContext();
1100
1101   if(aPlaneIndex+1 <= myPreviewPlaneVector.size()) {
1102     Handle(AIS_Plane) myPreviewPlane = myPreviewPlaneVector[aPlaneIndex];
1103     if ( !myPreviewPlane.IsNull() && ic->IsDisplayed( myPreviewPlane ) ) {
1104       ic->Erase( myPreviewPlane, false );
1105       ic->Remove( myPreviewPlane, false );
1106     }
1107     myPreviewPlaneVector.erase(myPreviewPlaneVector.begin() + aPlaneIndex);
1108   }
1109   synchronize();
1110   if (AutoApplyCheckBox->isChecked()) {
1111     onApply();
1112   }
1113   myModel->update();
1114 }
1115
1116 /*!
1117   SLOT on disable all button click: Restore initial state of viewer,
1118   erase all clipping planes
1119 */
1120 void OCCViewer_ClippingDlg::ClickOnDisableAll()
1121 {
1122   AutoApplyCheckBox->setChecked (false);
1123   int aClipPlanesCount = clipPlanesCount();
1124   for ( int anIndex = 0; anIndex < aClipPlanesCount; anIndex++)
1125   {
1126     OCCViewer_ClipPlane& aPlane = getClipPlane(anIndex);
1127     aPlane.IsOn = false;
1128   }
1129   erasePreview();
1130   isActivePlane->setChecked(false);
1131   myModel->setClipPlanes(myLocalPlanes);
1132   myModel->update();
1133 }
1134
1135 /*!
1136   SLOT on ok button click: sets cutting plane and closes dialog
1137 */
1138 void OCCViewer_ClippingDlg::ClickOnOk()
1139 {
1140   onApply();
1141   ClickOnClose();
1142 }
1143
1144 /*!
1145   SLOT on Apply button click: sets cutting plane and update viewer
1146 */
1147 void OCCViewer_ClippingDlg::ClickOnApply()
1148 {
1149   onApply();
1150   myModel->update();
1151 }
1152
1153 /*!
1154   SLOT on close button click: erases preview and rejects dialog
1155 */
1156 void OCCViewer_ClippingDlg::ClickOnClose()
1157 {
1158   erasePreview();
1159   OCCViewer_ViewWindow* v = qobject_cast<OCCViewer_ViewWindow*>(parent());
1160   if(v)
1161     v->onClipping(false);
1162 }
1163
1164 /*!
1165   SLOT on help button click: opens a help page
1166 */
1167 void OCCViewer_ClippingDlg::ClickOnHelp()
1168 {
1169   SUIT_Application* app = SUIT_Session::session()->activeApplication();
1170   if ( app )
1171     app->onHelpContextModule( "GUI", "occ_3d_viewer_page.html", "clipping_planes" );
1172 }
1173
1174 /*!
1175   Set absolute mode of clipping plane
1176 */
1177 void OCCViewer_ClippingDlg::onModeAbsolute()
1178 {
1179   myIsPlaneCreation = true;
1180   ModeStackedLayout->setCurrentIndex(0);
1181   ClickOnNew();
1182   myIsPlaneCreation = false;
1183   updateClipping();
1184 }
1185
1186 /*!
1187   Set relative mode of clipping plane
1188 */
1189 void OCCViewer_ClippingDlg::onModeRelative()
1190 {
1191   myIsPlaneCreation = true;
1192   ModeStackedLayout->setCurrentIndex(1);
1193   ClickOnNew();
1194   myIsPlaneCreation = false;
1195   SetCurrentPlaneParam();
1196   updateClipping();
1197 }
1198
1199 /*!
1200   SLOT: called on value of clipping plane changed
1201 */
1202 void OCCViewer_ClippingDlg::onValueChanged()
1203 {
1204   if ( myIsUpdatingControls )
1205   {
1206     return;
1207   }
1208
1209   SetCurrentPlaneParam();
1210
1211   if ( myIsSelectPlane )
1212   {
1213     return;
1214   }
1215
1216   updateClipping();
1217 }
1218
1219 /*!
1220   Set current parameters of selected plane
1221 */
1222 void OCCViewer_ClippingDlg::onSelectPlane ( int theIndex )
1223 {
1224   if ( clipPlanesCount() == 0 )
1225   {
1226     return;
1227   }
1228
1229   OCCViewer_ClipPlane& aClipPlane = getClipPlane( theIndex );
1230
1231   myIsSelectPlane = true;
1232   updateControls();
1233   ComboBoxPlanes->setCurrentIndex( theIndex );
1234   myIsSelectPlane = false;
1235 }
1236
1237 /*!
1238   Restore parameters of selected plane
1239 */
1240 void OCCViewer_ClippingDlg::SetCurrentPlaneParam()
1241 {
1242   if ( clipPlanesCount() == 0 || myIsSelectPlane || myBusy )
1243   {
1244     return;
1245   }
1246
1247   int aCurPlaneIndex = ComboBoxPlanes->currentIndex();
1248
1249   OCCViewer_ClipPlane& aPlane = getClipPlane( aCurPlaneIndex );
1250
1251   setPlaneParam( aPlane );
1252 }
1253
1254 /*!
1255   SLOT on reset button click: sets default values
1256 */
1257 void OCCViewer_ClippingDlg::onReset()
1258 {
1259   myBusy = true;
1260   SpinBox_X->setValue(0);
1261   SpinBox_Y->setValue(0);
1262   SpinBox_Z->setValue(0);
1263   myBusy = false;
1264
1265   SetCurrentPlaneParam();
1266   updateClipping();
1267 }
1268
1269 /*!
1270   SLOT on invert button click: inverts normal of cutting plane
1271 */
1272 void OCCViewer_ClippingDlg::onInvert()
1273 {
1274   double Dx = SpinBox_Dx->value();
1275   double Dy = SpinBox_Dy->value();
1276   double Dz = SpinBox_Dz->value();
1277
1278   myBusy = true;
1279   SpinBox_Dx->setValue( -Dx );
1280   SpinBox_Dy->setValue( -Dy );
1281   SpinBox_Dz->setValue( -Dz );
1282   myBusy = false;
1283
1284   if ( clipPlanesCount() != 0 )
1285   {
1286     int aCurPlaneIndex = ComboBoxPlanes->currentIndex();
1287     OCCViewer_ClipPlane& aPlane = getClipPlane( aCurPlaneIndex );
1288     aPlane.AbsoluteOrientation.IsInvert = !aPlane.AbsoluteOrientation.IsInvert;
1289   }
1290   updateClipping();
1291 }
1292
1293 /*!
1294   SLOT: called on orientation of clipping plane in absolute mode changed
1295 */
1296 void OCCViewer_ClippingDlg::onOrientationAbsoluteChanged( int mode )
1297 {
1298   bool isUserMode = (mode==0);
1299
1300   TextLabelX->setEnabled( isUserMode );
1301   TextLabelY->setEnabled( isUserMode );
1302   TextLabelZ->setEnabled( isUserMode );
1303
1304   SpinBox_X->setEnabled( isUserMode );
1305   SpinBox_Y->setEnabled( isUserMode );
1306   SpinBox_Z->setEnabled( isUserMode );
1307
1308   TextLabelDx->setEnabled( isUserMode );
1309   TextLabelDy->setEnabled( isUserMode );
1310   TextLabelDz->setEnabled( isUserMode );
1311
1312   SpinBox_Dx->setEnabled( isUserMode );
1313   SpinBox_Dy->setEnabled( isUserMode );
1314   SpinBox_Dz->setEnabled( isUserMode );
1315
1316   int aCurPlaneIndex = ComboBoxPlanes->currentIndex();
1317   OCCViewer_ClipPlane& aPlane = getClipPlane( aCurPlaneIndex );
1318   double aDx = 0, aDy = 0, aDz = 0;
1319
1320   if ( mode == 0 )
1321   {
1322     aDx = aPlane.AbsoluteOrientation.Dx;
1323     aDy = aPlane.AbsoluteOrientation.Dy;
1324     aDz = aPlane.AbsoluteOrientation.Dz;
1325   }
1326   else if ( mode == 1 )
1327   {
1328     aDz = 1;
1329     TextLabelZ->setEnabled( true );
1330     SpinBox_Z->setEnabled( true );
1331     SpinBox_Z->setFocus();
1332   }
1333   else if ( mode == 2 )
1334   {
1335     aDx = 1;
1336     TextLabelX->setEnabled( true );
1337     SpinBox_X->setEnabled( true );
1338     SpinBox_X->setFocus();
1339   }
1340   else if ( mode == 3 )
1341   {
1342     aDy = 1;
1343     TextLabelY->setEnabled( true );
1344     SpinBox_Y->setEnabled( true );
1345     SpinBox_Y->setFocus();
1346   }
1347     
1348   if ( aPlane.AbsoluteOrientation.IsInvert == true )
1349   {
1350     aDx = -aDx;
1351     aDy = -aDy;
1352     aDz = -aDz;
1353   }
1354     
1355   myBusy = true;
1356   SpinBox_Dx->setValue( aDx );
1357   SpinBox_Dy->setValue( aDy );
1358   SpinBox_Dz->setValue( aDz );
1359   myBusy = false;
1360
1361   if ( !myIsUpdatingControls )
1362   {
1363     SetCurrentPlaneParam();
1364     updateClipping();
1365   }
1366 }
1367
1368 /*!
1369   SLOT: called on orientation of clipping plane in relative mode changed
1370 */
1371 void OCCViewer_ClippingDlg::onOrientationRelativeChanged (int theItem)
1372 {
1373   if ( clipPlanesCount() == 0 )
1374     return;
1375   
1376   if ( theItem == 0 ) {
1377     TextLabelRotation1->setText( tr( "ROTATION_AROUND_X_Y2Z" ) );
1378     TextLabelRotation2->setText( tr( "ROTATION_AROUND_Y_X2Z" ) );
1379   }
1380   else if ( theItem == 1 ) {
1381     TextLabelRotation1->setText( tr( "ROTATION_AROUND_Y_Z2X" ) );
1382     TextLabelRotation2->setText( tr( "ROTATION_AROUND_Z_Y2X" ) );
1383   }
1384   else if ( theItem == 2 ) {
1385     TextLabelRotation1->setText( tr( "ROTATION_AROUND_Z_X2Y" ) );
1386     TextLabelRotation2->setText( tr( "ROTATION_AROUND_X_Z2Y" ) );
1387   }
1388
1389   if ( !myIsUpdatingControls )
1390   {
1391     if( (QComboBox*)sender() == CBRelativeOrientation )
1392     {
1393       SetCurrentPlaneParam();
1394     }
1395
1396     updateClipping();
1397   }
1398 }
1399
1400 /*!
1401   SLOT: called on preview check box toggled
1402 */
1403 void OCCViewer_ClippingDlg::onPreview( bool on )
1404 {
1405   erasePreview();
1406   if ( on ) 
1407     displayPreview();
1408 }
1409
1410 /*!
1411   SLOT: called on Auto Apply check box toggled
1412 */
1413 void OCCViewer_ClippingDlg::onAutoApply( bool toggled )
1414 {
1415   if ( toggled ) {
1416     onApply();
1417     myModel->update();
1418   }  
1419 }
1420
1421 /*!
1422   SLOT on Apply button click: sets cutting plane
1423 */
1424 void OCCViewer_ClippingDlg::onApply()
1425 {
1426   if ( myBusy )
1427     return;
1428   myIsSelectPlane = true;
1429
1430   qApp->processEvents();
1431   QApplication::setOverrideCursor( Qt::WaitCursor );
1432   qApp->processEvents();
1433
1434   myModel->setClipPlanes(myLocalPlanes);
1435
1436   QApplication::restoreOverrideCursor();
1437   myIsSelectPlane = false;
1438 }
1439
1440 /*!
1441   SLOT: Called when clip plane is clicked in viewer.
1442 */
1443 void OCCViewer_ClippingDlg::onPlaneClicked( const Handle(AIS_Plane)& thePlane )
1444 {
1445   for ( int aPlaneIt = 0; aPlaneIt < myPreviewPlaneVector.size(); aPlaneIt++ )
1446   {
1447     Handle(AIS_Plane)& aPlane = myPreviewPlaneVector.at( aPlaneIt );
1448     if ( aPlane != thePlane )
1449     {
1450       continue;
1451     }
1452
1453     ComboBoxPlanes->setCurrentIndex( aPlaneIt );
1454
1455     break;
1456   }
1457 }
1458
1459 /*!
1460   SLOT: Called when clip plane is changed by dragging in viewer.
1461 */
1462 void OCCViewer_ClippingDlg::onPlaneDragged( const Handle(AIS_Plane)& thePlane )
1463 {
1464   for ( int aPlaneIt = 0; aPlaneIt < myPreviewPlaneVector.size(); aPlaneIt++ )
1465   {
1466     Handle(AIS_Plane)& aPlane = myPreviewPlaneVector.at( aPlaneIt );
1467     if ( aPlane != thePlane )
1468     {
1469       continue;
1470     }
1471
1472     OCCViewer_ClipPlane& aClipPlane = getClipPlane( aPlaneIt );
1473
1474     gp_Pln aPln = thePlane->Component()->Pln();
1475     const gp_Pnt& aPlaneP = aPln.Location();
1476     const gp_Dir& aPlaneN = aPln.Axis().Direction();
1477
1478     aClipPlane.X  = aPlaneP.X();
1479     aClipPlane.Y  = aPlaneP.Y();
1480     aClipPlane.Z  = aPlaneP.Z();
1481
1482     if ( aClipPlane.Mode == OCCViewer_ClipPlane::Absolute )
1483     {
1484       if ( aClipPlane.OrientationType == OCCViewer_ClipPlane::AbsoluteCustom )
1485       {
1486         int anInvertCoeff = aClipPlane.AbsoluteOrientation.IsInvert ? 1 : -1;
1487         aClipPlane.AbsoluteOrientation.Dx = anInvertCoeff * aPlaneN.X();
1488         aClipPlane.AbsoluteOrientation.Dy = anInvertCoeff * aPlaneN.Y();
1489         aClipPlane.AbsoluteOrientation.Dz = anInvertCoeff * aPlaneN.Z();
1490       }
1491     }
1492     else
1493     {
1494       OCCViewer_ClipPlane::DXYZToRelative( aPlaneN.X(), aPlaneN.Y(), aPlaneN.Z(),
1495                                            aClipPlane.OrientationType,
1496                                            aClipPlane.RelativeOrientation.Rotation1,
1497                                            aClipPlane.RelativeOrientation.Rotation2 );
1498     }
1499
1500     myIsUpdatingControls = true;
1501     updateControls();
1502     myIsUpdatingControls = false;
1503
1504     if ( AutoApplyCheckBox->isChecked() )
1505     {
1506       onApply();
1507     }
1508
1509     break;
1510   }
1511 }
1512
1513 OCCViewer_ClipPlane& OCCViewer_ClippingDlg::getClipPlane( int theIdx )
1514 {
1515   return myLocalPlanes[theIdx];
1516 }
1517
1518 int OCCViewer_ClippingDlg::clipPlanesCount()
1519 {
1520   return myLocalPlanes.size();
1521 }
1522
1523 OCCViewer_ClipPlane::PlaneMode OCCViewer_ClippingDlg::currentPlaneMode() const
1524 {
1525   return ModeStackedLayout->currentIndex() == 0
1526     ? OCCViewer_ClipPlane::Absolute 
1527     : OCCViewer_ClipPlane::Relative;
1528 }