Salome HOME
allow SMESH publishing in GUI
[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 <OCCViewer_ViewModel.h>
23 #include <OCCViewer_ViewManager.h>
24 #include <QtxRubberBand.h>
25 #include <QApplication>
26 #include <QPainter>
27 #include <QMouseEvent>
28 #include <QLayout>
29
30 class HYDROGUI_OverviewBand : public QtxPolyRubberBand
31 {
32 public:
33   HYDROGUI_OverviewBand( HYDROGUI_Overview* theOverview );
34   virtual ~HYDROGUI_OverviewBand();
35
36   void initGeometry( const QPolygon& );
37   void update( bool isFromMain );
38   QPoint center() const;
39   int    count() const;
40
41   void   drag( const QPoint&, bool isStart );
42   bool   isDrag() const;
43   void   dragging( const QPoint& );
44   bool   contains( const QPoint& ) const;
45   QRect  boundingRect() const;
46
47 protected:
48   virtual void paintEvent( QPaintEvent* );
49
50 private:
51   HYDROGUI_Overview* myOverview;
52   bool               myIsDrag;
53   QPolygon           myStartPoints;
54   QPoint             myStartPnt;
55 };
56
57
58 HYDROGUI_OverviewBand::HYDROGUI_OverviewBand( HYDROGUI_Overview* theOverview )
59   : QtxPolyRubberBand( theOverview->getViewPort( false ) ),
60     myOverview( theOverview ), myIsDrag( false )
61 {
62 }
63
64 HYDROGUI_OverviewBand::~HYDROGUI_OverviewBand()
65 {
66 }
67
68 bool isEmpty( const QPolygon& thePoly )
69 {
70   QSize s = thePoly.boundingRect().size();
71   if( s.width() < 2 || s.height() < 2 )
72     return true;
73   else
74     return false;
75 }
76
77 void HYDROGUI_OverviewBand::initGeometry( const QPolygon& thePoly )
78 {
79   int w2 = myOverview->width()*2;
80   int h2 = myOverview->height()*2;
81
82   QPolygon aPoly;
83   for( int i=0, n=thePoly.size(); i<n; i++ )
84   {
85     QPoint p = thePoly.point( i );
86     if( p.x() < -w2 )
87       p.setX( -w2 );
88     if( p.x() > w2 )
89       p.setX( w2 );
90     if( p.y() < -h2 )
91       p.setY( -h2 );
92     if( p.y() > h2 )
93       p.setY( h2 );
94   }
95
96   QtxPolyRubberBand::initGeometry( thePoly );
97   if( isEmpty( thePoly ) )
98     hide();
99   else
100     show();
101 }
102
103 QRect HYDROGUI_OverviewBand::boundingRect() const
104 {
105   return myPoints.boundingRect();
106 }
107
108 QPoint HYDROGUI_OverviewBand::center() const
109 {
110   QPoint c;
111   int n = myPoints.size()-1;
112   if( n==0 )
113     return QPoint();
114
115   for( int i=0; i<n; i++ )
116     c += myPoints.point( i );
117
118   c = c/n;
119   return c;
120 }
121
122 void HYDROGUI_OverviewBand::drag( const QPoint& thePoint, bool isStart )
123 {
124   if( myIsDrag==isStart )
125     return;
126
127   if( isStart )
128   {
129     myStartPoints = myPoints;
130     /*if( contains( thePoint ) )
131       myStartPnt = thePoint;
132     else*/
133       myStartPnt = center();
134     myIsDrag = true;
135     dragging( thePoint );
136   }
137   else
138   {
139     dragging( thePoint );
140     myIsDrag = false;
141   }
142 }
143
144 bool HYDROGUI_OverviewBand::isDrag() const
145 {
146   return myIsDrag;
147 }
148
149 void HYDROGUI_OverviewBand::dragging( const QPoint& thePoint )
150 {
151   int n = myPoints.size();
152   QPoint delta = thePoint - myStartPnt;
153   for( int i=0; i<n; i++ )
154     myPoints.setPoint( i, myStartPoints.point( i ) + delta );
155   initGeometry( myPoints );
156   update( false );
157 }
158
159 bool HYDROGUI_OverviewBand::contains( const QPoint& thePoint ) const
160 {
161   return myPoints.containsPoint( thePoint, Qt::OddEvenFill );
162 }
163
164 int HYDROGUI_OverviewBand::count() const
165 {
166   return myPoints.size();
167 }
168
169 void HYDROGUI_OverviewBand::update( bool isFromMain )
170 {
171   OCCViewer_ViewPort3d* main = myOverview->getViewPort( true );
172   if( isFromMain )
173   {
174     int w = main->width();
175     int h = main->height();
176
177     QPolygon poly;
178     QPoint p1 = myOverview->fromMain( 0, 0 );
179     QPoint p2 = myOverview->fromMain( w, 0 );
180     QPoint p3 = myOverview->fromMain( w, h );
181     QPoint p4 = myOverview->fromMain( 0, h );
182     poly.append( p1 );
183     poly.append( p2 );
184     poly.append( p3 );
185     poly.append( p4 );
186     poly.append( p1 );
187     initGeometry( poly );
188   }
189   else
190   {
191     OCCViewer_ViewPort3d* overview = myOverview->getViewPort( false );
192     QPoint c = center();
193     double x1, y1, z1, x2, y2, z2;
194     main->getView()->Convert( main->width()/2, main->height()/2, x1, y1, z1 );
195
196     // Patch for OCCT 6.9.1, on 7.0.0 the moving of point to plane XY is not necessary
197     gp_Dir dm = main->getView()->Camera()->Direction();
198     double t1 = -z1/dm.Z();
199     x1 += dm.X()*t1;
200     y1 += dm.Y()*t1;
201     z1 += dm.Z()*t1;
202
203     overview->getView()->Convert( c.x(), c.y(), x2, y2, z2 );
204     gp_Dir dov = overview->getView()->Camera()->Direction();
205     double t2 = -z2/dov.Z();
206     x2 += dov.X()*t2;
207     y2 += dov.Y()*t2;
208     z2 += dov.Z()*t2;
209
210     gp_Trsf aTrsf;
211     aTrsf.SetTranslation( gp_Pnt( x1, y1, z1 ), gp_Pnt( x2, y2, z2 ) );
212
213     // Temporary patch for bug in OCCT 6.9.1
214     Handle(Graphic3d_Camera) cam = main->getView()->Camera();
215     gp_Dir u = cam->Up(), nu = u.Transformed (aTrsf);
216     gp_Pnt e = cam->Eye(), ne = e.Transformed (aTrsf);
217     gp_Pnt cen = cam->Center(), ncen = cen.Transformed (aTrsf);
218
219     if (!nu.IsEqual (u, 0.0))
220       cam->SetUp(nu);
221
222     if (!ne.IsEqual (e, 0.0))
223       cam->SetEye(ne);
224
225     if (!ncen.IsEqual(cen, 0.0))
226       cam->SetCenter (ncen);
227
228     //version for new OCCT:
229     //main->getView()->Camera()->Transform( aTrsf );
230     main->repaint();
231   }
232 }
233
234 void HYDROGUI_OverviewBand::paintEvent( QPaintEvent* thePaintEvent )
235 {
236   QPainter painter( this );
237   painter.setRenderHint( QPainter::Antialiasing );
238
239   static QColor aColor = Qt::red;
240   static int aWidth = 2;
241   static QPen aPen( QBrush( aColor ), aWidth, Qt::DashDotLine );
242
243   painter.setPen( aPen );
244   painter.drawPolygon( myPoints );
245 }
246
247 //////////////
248
249 HYDROGUI_Overview::HYDROGUI_Overview( const QString& theTitle, int theMargin, QWidget* theParent )
250   : QFrame( theParent ), myMargin( theMargin ),
251     myMainView( 0 ), myViewPort( 0 ), myBand( 0 )
252 {
253   setWindowTitle( theTitle );
254   myLayout = new QGridLayout( this );
255   myLayout->setMargin( 0 );
256   myLayout->setSpacing( 0 );
257   myLayout->setRowStretch( 0, 1 );
258   myLayout->setColumnStretch( 0, 1 );
259 }
260
261 HYDROGUI_Overview::~HYDROGUI_Overview()
262 {
263   //delete myViewPort;
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
280 #if OCC_VERSION_LARGE >= 0x07020000
281   view->ToPixMap( aPix,aWidth, aHeight,Graphic3d_BT_RGBA );
282   QImage anImage( aPix.Data(), aWidth, aHeight, QImage::Format_ARGB32 );
283   anImage = anImage.mirrored();
284   anImage = anImage.rgbSwapped();
285 #else
286   view->ToPixMap(aPix, aWidth, aHeight, Graphic3d_BT_RGB);
287   QImage anImage( aWidth, aHeight, QImage::Format_ARGB32 );
288   for ( int i = 0; i < aWidth; i++ ) {
289     for ( int j = 0; j < aHeight; j++ ) {
290       Quantity_Color pixel = aPix.PixelColor( i, j ).GetRGB();
291       QColor color = QColor::fromRgbF( pixel.Red(), pixel.Green(), pixel.Blue() );
292       anImage.setPixelColor( i, j, color );
293     }
294   }
295   if ( aPix.IsTopDown() )
296     anImage = anImage.mirrored();
297 #endif
298   if( myBand && myBand->isVisible() )
299   {
300     QPixmap aPixmap = QPixmap::fromImage( anImage );
301     QPoint p = myBand->boundingRect().topLeft();
302     myBand->render( &aPixmap, p );
303     anImage = aPixmap.toImage();
304   }
305   return anImage;
306 }
307
308 OCCViewer_ViewPort3d* HYDROGUI_Overview::getViewPort( bool isMain ) const
309 {
310   if ( isMain) 
311   {
312     if (myMainView!=NULL)
313       return myMainView->getViewPort();
314     else
315       return NULL;
316   }
317   else
318     return myViewPort;
319 }
320
321 void HYDROGUI_Overview::setMainView( OCCViewer_ViewFrame* theMainView )
322 {
323   myMainView = theMainView;
324   if( !myMainView )
325     return;
326
327   OCCViewer_ViewWindow* aMainView = myMainView->getView( OCCViewer_ViewFrame::MAIN_VIEW );
328   connect( aMainView, SIGNAL( vpTransformationFinished( OCCViewer_ViewWindow::OperationType ) ),
329            this,      SLOT( OnTransformationAfterOp( OCCViewer_ViewWindow::OperationType ) ) );
330   connect( aMainView->getViewPort(), SIGNAL( vpResizeEvent( QResizeEvent* ) ),
331            this,       SLOT( OnResizeEvent( QResizeEvent* ) ) );
332   connect( aMainView->getViewPort(), SIGNAL( vpTransformed( OCCViewer_ViewPort* ) ),
333            this,       SLOT( OnTransformation() ) ); 
334
335   connect( myMainView, SIGNAL(destroyed()),  this,  SLOT( onMainViewDestr() ) );
336   connect( myViewPort, SIGNAL(destroyed()),  this,  SLOT( onViewPortDestr() ) );
337
338   if( !myViewPort )
339   {
340     myViewPort = new OCCViewer_ViewPort3d( this, myMainView->getViewPort()->getViewer(), V3d_ORTHOGRAPHIC );
341
342     if( myViewPort )
343     {
344       myViewPort->setBackgroundColor( myMainView->getViewPort()->backgroundColor() );
345
346       connect( myViewPort, SIGNAL( vpMouseEvent( QMouseEvent* ) ), 
347               this,       SLOT( OnMouseEvent( QMouseEvent* ) ) );
348       connect( myViewPort, SIGNAL( vpResizeEvent( QResizeEvent* ) ),
349               this,       SLOT( OnResizeEvent( QResizeEvent* ) ) );
350
351       myLayout->addWidget( myViewPort, 0, 0 );
352     }
353   }
354
355 #if defined(TEST_MODE) || defined(_DEBUG)
356   //qApp->installEventFilter( this );
357 #endif
358
359   qApp->processEvents();
360
361   setTopView();
362
363   qApp->processEvents();
364
365   if( !myBand )
366     myBand = new HYDROGUI_OverviewBand( this );
367
368   myBand->update( true );
369 }
370
371 void HYDROGUI_Overview::setTopView()
372 {
373   if( !myViewPort )
374     return;
375
376   Handle(V3d_View) aView3d = myViewPort->getView();
377   if( !aView3d.IsNull() )
378     aView3d->SetProj( V3d_Zpos );
379   myViewPort->fitAll();
380
381   // Apply margins for internal area in the view port
382   if( myMargin>0 )
383   {
384     QRect aRect( -myMargin, -myMargin, myViewPort->width()+2*myMargin, myViewPort->height()+2*myMargin );
385     myViewPort->fitRect( aRect );
386   }
387
388   if( myBand )
389     myBand->update( true );
390 }
391
392 void HYDROGUI_Overview::OnTransformationAfterOp( OCCViewer_ViewWindow::OperationType theOp )
393 {
394   if( myViewPort && theOp>=OCCViewer_ViewWindow::WINDOWFIT )
395   {
396     myViewPort->fitAll();
397   }
398   if( theOp==OCCViewer_ViewWindow::FITSELECTION )
399   {
400     CustomFitSelection();
401   }
402   OnTransformation();
403 }
404
405 void HYDROGUI_Overview::OnTransformation()
406 {
407   if( myBand )
408     myBand->update( true );
409 }
410
411 QPoint HYDROGUI_Overview::fromMain( int xp, int yp ) const
412 {
413   if( !myMainView || !myViewPort || !myViewPort->isVisible() )
414     return QPoint();
415
416   const double EPS = 1E-2;
417
418   Handle(V3d_View) aMain = myMainView->getViewPort()->getView();
419   Handle(V3d_View) aXY = myViewPort->getView();
420
421   // View coordinates to 3d (world) coordinates
422   double x, y, z;
423   aMain->Convert( xp, yp, x, y, z );
424
425   // Moving to the XY plane
426   gp_Vec aDir = aMain->Camera()->Direction();
427   if( fabs( aDir.Z() )<EPS )
428     return QPoint();
429
430   double t = -z/aDir.Z();
431   x += t * aDir.X();
432   y += t * aDir.Y();
433   z += t * aDir.Z();
434
435   // 3d (world) coordinates to view coordinates in the overview
436   aXY->Convert( x, y, z, xp, yp );
437
438   return QPoint( xp, yp );
439 }
440
441 void HYDROGUI_Overview::OnMouseEvent( QMouseEvent* theEvent )
442 {
443   QPoint mp = theEvent->pos();
444   if( !myBand )
445     return;
446
447   switch( theEvent->type() )
448   {
449   case QEvent::MouseButtonPress:
450     myBand->drag( mp, true );
451     break;
452
453   case QEvent::MouseButtonRelease:
454     myBand->drag( mp, false );
455     break;
456
457   case QEvent::MouseMove:
458     if( myBand->isDrag() )
459       myBand->dragging( mp );
460     break;
461   }
462 }
463
464 bool HYDROGUI_Overview::eventFilter( QObject* theObject, QEvent* theEvent )
465 {
466 #if defined(TEST_MODE) || defined(_DEBUG)
467   /*switch( theEvent->type() )
468   {
469   case QEvent::MouseMove:
470     {
471       QPoint mp = ((QMouseEvent*)theEvent)->pos();
472       //mp = getViewPort(false)->mapFromGlobal(mp);
473       QString coords = QString( "(%0, %1)" ).arg( mp.x() ).arg( mp.y() );
474       std::string scoords = coords.toStdString();
475       qDebug( scoords.c_str() );
476     }
477     break;
478   }*/
479 #endif
480   return QFrame::eventFilter( theObject, theEvent );
481 }
482
483 void HYDROGUI_Overview::OnResizeEvent( QResizeEvent* )
484 {
485   if( myBand )
486     myBand->update( true );
487 }
488
489
490 void HYDROGUI_Overview::onMainViewDestr()
491 {
492   myMainView = NULL;
493   if (myViewPort == NULL)
494     return;
495   Handle(V3d_View) ov = myViewPort->getView();
496   ov->View()->Deactivate();
497   delete myViewPort; //this will delete myBand
498   myViewPort = NULL;
499   myBand = NULL;
500 }
501
502 void HYDROGUI_Overview::onViewPortDestr()
503 {
504   myViewPort = NULL;
505 }
506
507
508 void HYDROGUI_Overview::CustomFitSelection() const
509 {
510   OCCViewer_ViewPort3d* main = getViewPort( true );
511   if( !main )
512     return;
513
514   int w = main->width();
515   int h = main->height();
516
517   Bnd_Box bounding = BoundingForSelection();
518   if( bounding.IsVoid() )
519     return;
520
521   Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
522   bounding.Get( xmin, ymin, zmin, xmax, ymax, zmax );
523
524   QList<QPoint> points;
525   Standard_Integer xp, yp;
526   main->getView()->Convert( xmin, ymin, zmin, xp, yp ); points.append( QPoint( xp, yp ) );
527   main->getView()->Convert( xmax, ymin, zmin, xp, yp ); points.append( QPoint( xp, yp ) );
528   main->getView()->Convert( xmin, ymax, zmin, xp, yp ); points.append( QPoint( xp, yp ) );
529   main->getView()->Convert( xmax, ymax, zmin, xp, yp ); points.append( QPoint( xp, yp ) );
530   main->getView()->Convert( xmin, ymin, zmax, xp, yp ); points.append( QPoint( xp, yp ) );
531   main->getView()->Convert( xmax, ymin, zmax, xp, yp ); points.append( QPoint( xp, yp ) );
532   main->getView()->Convert( xmin, ymax, zmax, xp, yp ); points.append( QPoint( xp, yp ) );
533   main->getView()->Convert( xmax, ymax, zmax, xp, yp ); points.append( QPoint( xp, yp ) );
534
535   int xpmin, ypmin, xpmax, ypmax;
536   bool isFirst = true;
537   foreach( QPoint p, points )
538   {
539     int x = p.x(), y = p.y();
540     if( isFirst || x<xpmin )
541       xpmin = x;
542     if( isFirst || x>xpmax )
543       xpmax = x;
544     if( isFirst || y<ypmin )
545       ypmin = y;
546     if( isFirst || y>ypmax )
547       ypmax = y;
548
549     isFirst = false;
550   }
551
552   const int margin = 5;
553   QRect r( xpmin-margin, ypmin-margin, xpmax-xpmin+2*margin, ypmax-ypmin+2*margin );
554   main->fitRect( r );
555 }
556
557 Handle(AIS_InteractiveContext) HYDROGUI_Overview::context() const
558 {
559   if( myMainView )
560   {
561     SUIT_ViewModel* vm = myMainView->getViewManager()->getViewModel();
562     OCCViewer_Viewer* viewer = dynamic_cast<OCCViewer_Viewer*>( vm );
563     if( viewer )
564       return viewer->getAISContext();
565   }
566   return Handle(AIS_InteractiveContext)();
567 }
568
569 typedef NCollection_DataMap<Handle(SelectMgr_SelectableObject), Handle(SelectMgr_IndexedMapOfOwner)> AIS_MapOfObjectOwners1;
570   typedef NCollection_DataMap<Handle(SelectMgr_SelectableObject), Handle(SelectMgr_IndexedMapOfOwner)>::Iterator AIS_MapIteratorOfMapOfObjectOwners1;
571 Bnd_Box HYDROGUI_Overview::BoundingForSelection() const
572 {
573   Handle(AIS_InteractiveContext) c = context();
574
575   Bnd_Box aBndSelected;
576
577   AIS_MapOfObjectOwners1 anObjectOwnerMap;
578   for (c->InitSelected(); c->MoreSelected(); c->NextSelected())
579   {
580     const Handle(SelectMgr_EntityOwner)& anOwner = c->SelectedOwner();
581     Handle(AIS_InteractiveObject) anObj = Handle(AIS_InteractiveObject)::DownCast(anOwner->Selectable());
582     if (anObj->IsInfinite())
583     {
584       continue;
585     }
586
587     if (anOwner == anObj->GlobalSelOwner())
588     {
589       Bnd_Box aTmpBnd;
590       anObj->BoundingBox (aTmpBnd);
591       aBndSelected.Add (aTmpBnd);
592     }
593     else
594     {
595       Handle(SelectMgr_IndexedMapOfOwner) anOwnerMap;
596       if (!anObjectOwnerMap.Find (anOwner->Selectable(), anOwnerMap))
597       {
598         anOwnerMap = new SelectMgr_IndexedMapOfOwner();
599         anObjectOwnerMap.Bind (anOwner->Selectable(), anOwnerMap);
600       }
601
602       anOwnerMap->Add (anOwner);
603     }
604   }
605
606   for (AIS_MapIteratorOfMapOfObjectOwners1 anIter (anObjectOwnerMap); anIter.More(); anIter.Next())
607   {
608     const Handle(SelectMgr_SelectableObject) anObject = anIter.Key();
609     Bnd_Box aTmpBox = anObject->BndBoxOfSelected (anIter.ChangeValue());
610     aBndSelected.Add (aTmpBox);
611   }
612
613   anObjectOwnerMap.Clear();
614
615   return aBndSelected;
616 }