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