Salome HOME
refs #1382: when user clicks the current position becomes center
[modules/hydro.git] / src / HYDROGUI / HYDROGUI_Overview.cxx
1 // Copyright (C) 2014-2015  EDF-R&D
2 // This library is free software; you can redistribute it and/or
3 // modify it under the terms of the GNU Lesser General Public
4 // License as published by the Free Software Foundation; either
5 // version 2.1 of the License, or (at your option) any later version.
6 //
7 // This library is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10 // Lesser General Public License for more details.
11 //
12 // You should have received a copy of the GNU Lesser General Public
13 // License along with this library; if not, write to the Free Software
14 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15 //
16 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
17 //
18
19 #include <HYDROGUI_Overview.h>
20 #include <OCCViewer_ViewPort3d.h>
21 #include <OCCViewer_ViewFrame.h>
22 #include <QtxRubberBand.h>
23 #include <QApplication>
24 #include <QPainter>
25 #include <QMouseEvent>
26 #include <QLayout>
27
28 class HYDROGUI_OverviewBand : public QtxPolyRubberBand
29 {
30 public:
31   HYDROGUI_OverviewBand( HYDROGUI_Overview* theOverview );
32   virtual ~HYDROGUI_OverviewBand();
33
34   void initGeometry( const QPolygon& );
35   void update( bool isFromMain );
36   QPoint center() const;
37   int    count() const;
38
39   void   drag( const QPoint&, bool isStart );
40   bool   isDrag() const;
41   void   dragging( const QPoint& );
42   bool   contains( const QPoint& ) const;
43   QRect  boundingRect() const;
44
45 protected:
46   virtual void paintEvent( QPaintEvent* );
47
48 private:
49   HYDROGUI_Overview* myOverview;
50   bool               myIsDrag;
51   QPolygon           myStartPoints;
52   QPoint             myStartPnt;
53 };
54
55
56 HYDROGUI_OverviewBand::HYDROGUI_OverviewBand( HYDROGUI_Overview* theOverview )
57   : QtxPolyRubberBand( theOverview->getViewPort( false ) ),
58     myOverview( theOverview ), myIsDrag( false )
59 {
60 }
61
62 HYDROGUI_OverviewBand::~HYDROGUI_OverviewBand()
63 {
64 }
65
66 bool isEmpty( const QPolygon& thePoly )
67 {
68   QSize s = thePoly.boundingRect().size();
69   if( s.width() < 2 || s.height() < 2 )
70     return true;
71   else
72     return false;
73 }
74
75 void HYDROGUI_OverviewBand::initGeometry( const QPolygon& thePoly )
76 {
77   int w2 = myOverview->width()*2;
78   int h2 = myOverview->height()*2;
79
80   QPolygon aPoly;
81   for( int i=0, n=thePoly.size(); i<n; i++ )
82   {
83     QPoint p = thePoly.point( i );
84     if( p.x() < -w2 )
85       p.setX( -w2 );
86     if( p.x() > w2 )
87       p.setX( w2 );
88     if( p.y() < -h2 )
89       p.setY( -h2 );
90     if( p.y() > h2 )
91       p.setY( h2 );
92   }
93
94   QtxPolyRubberBand::initGeometry( thePoly );
95   if( isEmpty( thePoly ) )
96     hide();
97   else
98     show();
99 }
100
101 QRect HYDROGUI_OverviewBand::boundingRect() const
102 {
103   return myPoints.boundingRect();
104 }
105
106 QPoint HYDROGUI_OverviewBand::center() const
107 {
108   QPoint c;
109   int n = myPoints.size()-1;
110   if( n==0 )
111     return QPoint();
112
113   for( int i=0; i<n; i++ )
114     c += myPoints.point( i );
115
116   c = c/n;
117   return c;
118 }
119
120 void HYDROGUI_OverviewBand::drag( const QPoint& thePoint, bool isStart )
121 {
122   if( myIsDrag==isStart )
123     return;
124
125   if( isStart )
126   {
127     myStartPoints = myPoints;
128     /*if( contains( thePoint ) )
129       myStartPnt = thePoint;
130     else*/
131       myStartPnt = center();
132     myIsDrag = true;
133     dragging( thePoint );
134   }
135   else
136   {
137     dragging( thePoint );
138     myIsDrag = false;
139   }
140 }
141
142 bool HYDROGUI_OverviewBand::isDrag() const
143 {
144   return myIsDrag;
145 }
146
147 void HYDROGUI_OverviewBand::dragging( const QPoint& thePoint )
148 {
149   int n = myPoints.size();
150   QPoint delta = thePoint - myStartPnt;
151   for( int i=0; i<n; i++ )
152     myPoints.setPoint( i, myStartPoints.point( i ) + delta );
153   initGeometry( myPoints );
154   update( false );
155 }
156
157 bool HYDROGUI_OverviewBand::contains( const QPoint& thePoint ) const
158 {
159   return myPoints.containsPoint( thePoint, Qt::OddEvenFill );
160 }
161
162 int HYDROGUI_OverviewBand::count() const
163 {
164   return myPoints.size();
165 }
166
167 void HYDROGUI_OverviewBand::update( bool isFromMain )
168 {
169   OCCViewer_ViewPort3d* main = myOverview->getViewPort( true );
170   if( isFromMain )
171   {
172     int w = main->width();
173     int h = main->height();
174
175     QPolygon poly;
176     QPoint p1 = myOverview->fromMain( 0, 0 );
177     QPoint p2 = myOverview->fromMain( w, 0 );
178     QPoint p3 = myOverview->fromMain( w, h );
179     QPoint p4 = myOverview->fromMain( 0, h );
180     poly.append( p1 );
181     poly.append( p2 );
182     poly.append( p3 );
183     poly.append( p4 );
184     poly.append( p1 );
185     initGeometry( poly );
186   }
187   else
188   {
189     OCCViewer_ViewPort3d* overview = myOverview->getViewPort( false );
190     QPoint c = center();
191     double x1, y1, z1, x2, y2, z2;
192     main->getView()->Convert( main->width()/2, main->height()/2, x1, y1, z1 );
193
194     // Patch for OCCT 6.9.1, on 7.0.0 the moving of point to plane XY is not necessary
195     gp_Dir dm = main->getView()->Camera()->Direction();
196     double t1 = -z1/dm.Z();
197     x1 += dm.X()*t1;
198     y1 += dm.Y()*t1;
199     z1 += dm.Z()*t1;
200
201     overview->getView()->Convert( c.x(), c.y(), x2, y2, z2 );
202     gp_Dir dov = overview->getView()->Camera()->Direction();
203     double t2 = -z2/dov.Z();
204     x2 += dov.X()*t2;
205     y2 += dov.Y()*t2;
206     z2 += dov.Z()*t2;
207
208     gp_Trsf aTrsf;
209     aTrsf.SetTranslation( gp_Pnt( x1, y1, z1 ), gp_Pnt( x2, y2, z2 ) );
210
211     // Temporary patch for bug in OCCT 6.9.1
212     Handle(Graphic3d_Camera) cam = main->getView()->Camera();
213     gp_Dir u = cam->Up(), nu = u.Transformed (aTrsf);
214     gp_Pnt e = cam->Eye(), ne = e.Transformed (aTrsf);
215     gp_Pnt cen = cam->Center(), ncen = cen.Transformed (aTrsf);
216
217     if (!nu.IsEqual (u, 0.0))
218       cam->SetUp(nu);
219
220     if (!ne.IsEqual (e, 0.0))
221       cam->SetEye(ne);
222
223     if (!ncen.IsEqual(cen, 0.0))
224       cam->SetCenter (ncen);
225
226     //version for new OCCT:
227     //main->getView()->Camera()->Transform( aTrsf );
228     main->repaint();
229   }
230 }
231
232 void HYDROGUI_OverviewBand::paintEvent( QPaintEvent* thePaintEvent )
233 {
234   QPainter painter( this );
235   painter.setRenderHint( QPainter::Antialiasing );
236
237   static QColor aColor = Qt::red;
238   static int aWidth = 2;
239   static QPen aPen( QBrush( aColor ), aWidth, Qt::SolidLine );
240
241   painter.setPen( aPen );
242   painter.drawPolygon( myPoints );
243 }
244
245
246
247
248
249
250 HYDROGUI_Overview::HYDROGUI_Overview( const QString& theTitle, int theMargin, QWidget* theParent )
251   : QFrame( theParent ), myMargin( theMargin ),
252     myMainView( 0 ), myViewPort( 0 ), myBand( 0 )
253 {
254   setWindowTitle( theTitle );
255   myLayout = new QGridLayout( this );
256   myLayout->setMargin( 0 );
257   myLayout->setSpacing( 0 );
258   myLayout->setRowStretch( 0, 1 );
259   myLayout->setColumnStretch( 0, 1 );
260 }
261
262 HYDROGUI_Overview::~HYDROGUI_Overview()
263 {
264 }
265
266 QImage HYDROGUI_Overview::dump() const
267 {
268   if( !myViewPort )
269     return QImage();
270
271   Handle(V3d_View) view = myViewPort->getView();
272   if( view.IsNull() )
273     return QImage();
274
275   int aWidth = myViewPort->width();
276   int aHeight = myViewPort->height();
277
278   Image_PixMap aPix;
279   view->ToPixMap( aPix,aWidth, aHeight,Graphic3d_BT_RGBA );
280
281   QImage anImage( aPix.Data(), aWidth, aHeight, QImage::Format_ARGB32 );
282   anImage = anImage.mirrored();
283   anImage = anImage.rgbSwapped();
284
285   if( myBand && myBand->isVisible() )
286   {
287     QPixmap aPixmap = QPixmap::fromImage( anImage );
288     QPoint p = myBand->boundingRect().topLeft();
289     myBand->render( &aPixmap, p );
290     anImage = aPixmap.toImage();
291   }
292
293   return anImage;
294 }
295
296 OCCViewer_ViewPort3d* HYDROGUI_Overview::getViewPort( bool isMain ) const
297 {
298   return isMain ? myMainView->getViewPort() : myViewPort;
299 }
300
301 void HYDROGUI_Overview::setMainView( OCCViewer_ViewFrame* theMainView )
302 {
303   myMainView = theMainView;
304   if( !myMainView )
305     return;
306
307   OCCViewer_ViewWindow* aMainView = myMainView->getView( OCCViewer_ViewFrame::MAIN_VIEW );
308   connect( aMainView, SIGNAL( vpTransformationFinished( OCCViewer_ViewWindow::OperationType ) ),
309            this,      SLOT( OnTransformationAfterOp( OCCViewer_ViewWindow::OperationType ) ) );
310   connect( aMainView->getViewPort(), SIGNAL( vpResizeEvent( QResizeEvent* ) ),
311            this,       SLOT( OnResizeEvent( QResizeEvent* ) ) );
312   connect( aMainView->getViewPort(), SIGNAL( vpTransformed( OCCViewer_ViewPort* ) ),
313            this,       SLOT( OnTransformation() ) );
314
315   if( !myViewPort )
316   {
317     myViewPort = new OCCViewer_ViewPort3d( this, myMainView->getViewPort()->getViewer(), V3d_ORTHOGRAPHIC );
318     myViewPort->setBackgroundColor( myMainView->getViewPort()->backgroundColor() );
319
320     connect( myViewPort, SIGNAL( vpMouseEvent( QMouseEvent* ) ), 
321             this,       SLOT( OnMouseEvent( QMouseEvent* ) ) );
322     connect( myViewPort, SIGNAL( vpResizeEvent( QResizeEvent* ) ),
323             this,       SLOT( OnResizeEvent( QResizeEvent* ) ) );
324
325     myLayout->addWidget( myViewPort, 0, 0 );
326   }
327
328 #if defined(TEST_MODE) || defined(_DEBUG)
329   //qApp->installEventFilter( this );
330 #endif
331
332   qApp->processEvents();
333
334   setTopView();
335
336   qApp->processEvents();
337
338   if( !myBand )
339     myBand = new HYDROGUI_OverviewBand( this );
340
341   myBand->update( true );
342 }
343
344 void HYDROGUI_Overview::setTopView()
345 {
346   Handle(V3d_View) aView3d = myViewPort->getView();
347   if( !aView3d.IsNull() )
348     aView3d->SetProj( V3d_Zpos );
349   myViewPort->fitAll();
350
351   // Apply margins for internal area in the view port
352   if( myMargin>0 )
353   {
354     QRect aRect( -myMargin, -myMargin, myViewPort->width()+2*myMargin, myViewPort->height()+2*myMargin );
355     myViewPort->fitRect( aRect );
356   }
357
358   if( myBand )
359     myBand->update( true );
360 }
361
362 void HYDROGUI_Overview::OnTransformationAfterOp( OCCViewer_ViewWindow::OperationType theOp )
363 {
364   if( theOp>=OCCViewer_ViewWindow::WINDOWFIT )
365   {
366     myViewPort->fitAll();
367   }
368   OnTransformation();
369 }
370
371 void HYDROGUI_Overview::OnTransformation()
372 {
373   if( myBand )
374     myBand->update( true );
375 }
376
377 QPoint HYDROGUI_Overview::fromMain( int xp, int yp ) const
378 {
379   const double EPS = 1E-2;
380
381   Handle(V3d_View) aMain = myMainView->getViewPort()->getView();
382   Handle(V3d_View) aXY = myViewPort->getView();
383
384   // View coordinates to 3d (world) coordinates
385   double x, y, z;
386   aMain->Convert( xp, yp, x, y, z );
387
388   // Moving to the XY plane
389   gp_Vec aDir = aMain->Camera()->Direction();
390   if( fabs( aDir.Z() )<EPS )
391     return QPoint();
392
393   double t = -z/aDir.Z();
394   x += t * aDir.X();
395   y += t * aDir.Y();
396   z += t * aDir.Z();
397
398   // 3d (world) coordinates to view coordinates in the overview
399   aXY->Convert( x, y, z, xp, yp );
400
401   return QPoint( xp, yp );
402 }
403
404 void HYDROGUI_Overview::OnMouseEvent( QMouseEvent* theEvent )
405 {
406   QPoint mp = theEvent->pos();
407   if( !myBand )
408     return;
409
410   switch( theEvent->type() )
411   {
412   case QEvent::MouseButtonPress:
413     myBand->drag( mp, true );
414     break;
415
416   case QEvent::MouseButtonRelease:
417     myBand->drag( mp, false );
418     break;
419
420   case QEvent::MouseMove:
421     if( myBand->isDrag() )
422       myBand->dragging( mp );
423     break;
424   }
425 }
426
427 bool HYDROGUI_Overview::eventFilter( QObject* theObject, QEvent* theEvent )
428 {
429 #if defined(TEST_MODE) || defined(_DEBUG)
430   /*switch( theEvent->type() )
431   {
432   case QEvent::MouseMove:
433     {
434       QPoint mp = ((QMouseEvent*)theEvent)->pos();
435       //mp = getViewPort(false)->mapFromGlobal(mp);
436       QString coords = QString( "(%0, %1)" ).arg( mp.x() ).arg( mp.y() );
437       std::string scoords = coords.toStdString();
438       qDebug( scoords.c_str() );
439     }
440     break;
441   }*/
442 #endif
443   return QFrame::eventFilter( theObject, theEvent );
444 }
445
446 void HYDROGUI_Overview::OnResizeEvent( QResizeEvent* )
447 {
448   if( myBand )
449     myBand->update( true );
450 }