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