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