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