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