1 // Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include "OCCViewer_ViewPort3d.h"
25 #include "OCCViewer_VService.h"
26 #include "OCCViewer_ViewWindow.h"
27 #include "OCCViewer_ViewModel.h"
29 #include <Basics_OCCTVersion.hxx>
31 #include <SUIT_ViewManager.h>
32 #include <SUIT_ViewModel.h>
38 #include <QPaintEvent>
39 #include <QResizeEvent>
40 #include <QApplication>
42 #include <Visual3d_View.hxx>
43 #include <V3d_Viewer.hxx>
44 #include <V3d_PerspectiveView.hxx>
45 #include <V3d_OrthographicView.hxx>
47 #include "utilities.h"
50 #include <WNT_Window.hxx>
52 #include <Xw_Window.hxx>
55 static double rx = 0.;
56 static double ry = 0.;
59 static Standard_Boolean zRotation = Standard_False;
61 //#include <Standard_Version.hxx>
66 OCCViewer_ViewPort3d::OCCViewer_ViewPort3d( QWidget* parent, const Handle( V3d_Viewer)& viewer, V3d_TypeOfView type )
67 : OCCViewer_ViewPort( parent ),
70 myIsAdvancedZoomingEnabled( false )
72 // VSR: 01/07/2010 commented to avoid SIGSEGV at SALOME exit
75 if ( type == V3d_ORTHOGRAPHIC ) {
76 myOrthoView = new V3d_OrthographicView( viewer );
77 myActiveView = myOrthoView;
80 myPerspView = new V3d_PerspectiveView( viewer );
81 myActiveView = myPerspView;
83 setBackground( Qtx::BackgroundData( Qt::black ) ); // set default background
89 OCCViewer_ViewPort3d::~OCCViewer_ViewPort3d()
92 Handle(V3d_View) aView = activeView();
98 Activates the desired 'type' of view in the viewer
99 ( view of 'type' is created if it doesn't exist ). [ public ]
101 /*void OCCViewer_ViewPort3d::setActive( V3d_TypeOfView type )
103 if ( activeView().IsNull() )
106 if ( activeView()->Type() != type )
108 if ( type == V3d_ORTHOGRAPHIC )
109 setView( myOrthoView );
110 if ( type == V3d_PERSPECTIVE )
111 setView( myPerspView );
116 Maps CasCade 'view' to this viewport. [ private ]
118 bool OCCViewer_ViewPort3d::mapView( const Handle(V3d_View)& view )
120 if ( !setWindow( view ) )
123 if ( !mapped( view ) ) {
124 view->SetWindow( myWindow );
125 if ( view != activeView() )
126 view->View()->Deactivate();
129 /* create static trihedron (16551: EDF PAL 501) */
130 OCCViewer_ViewWindow* aVW = dynamic_cast<OCCViewer_ViewWindow*>( parentWidget()->parentWidget()->parentWidget() );
132 OCCViewer_Viewer* aViewModel = dynamic_cast<OCCViewer_Viewer*>( aVW->getViewManager()->getViewModel() );
133 if ( aViewModel && aViewModel->isStaticTrihedronDisplayed() ){
134 view->ZBufferTriedronSetup();
135 view->TriedronDisplay( Aspect_TOTP_LEFT_LOWER, Quantity_NOC_WHITE, 0.05, V3d_ZBUFFER );
144 Sets new CASCADE view on viewport. Returns the previous active view. [ public ]
146 Handle( V3d_View ) OCCViewer_ViewPort3d::setView( const Handle( V3d_View )& view )
148 /* map the new view */
149 if ( view == activeView() || !mapView( view ) )
152 /* activate the new view*/
153 Handle( V3d_View ) oldView = activeView();
154 if ( !oldView.IsNull() ) {
155 if (oldView->View()->IsDefined())
156 oldView->View()->Deactivate();
157 view->SetBackgroundColor( oldView->BackgroundColor() );
160 view->View()->Activate();
166 Returns CasCade 3D view. [ public ]
168 Handle(V3d_View) OCCViewer_ViewPort3d::getView() const
174 Returns CasCade 3D viewer [ public ]
176 Handle(V3d_Viewer) OCCViewer_ViewPort3d::getViewer() const
178 Handle(V3d_Viewer) viewer;
179 if ( !activeView().IsNull() )
180 viewer = activeView()->Viewer();
185 Syncronizes visual state of this viewport with 'ref'
186 ( scale, projection, eye etc ) Returns 'true' if copied OK,
187 'false' otherwise. [ virtual public ]
189 bool OCCViewer_ViewPort3d::syncronize( const OCCViewer_ViewPort3d* ref )
191 OCCViewer_ViewPort3d* ref3d = (OCCViewer_ViewPort3d*)ref;
192 Handle(V3d_View) refView = ref3d->getView();
193 Handle(V3d_View) tgtView = getView();
195 /* Syncronize view types */
196 /* if ( tgtView->Type() != refView->Type() )
198 setActive( refView->Type() );
202 /* The following params are copied:
203 - view type( ortho/persp )
204 - position of view point
205 - orientation of high point
206 - position of the eye
213 /* we'll update after setting all params */
214 tgtView->SetImmediateUpdate( Standard_False );
217 if ( refView->Type() == V3d_PERSPECTIVE )
218 tgtView->SetFocale( refView->Focale() );
221 Standard_Real x, y, z;
222 refView->At( x, y, z ); tgtView->SetAt( x, y, z );
223 refView->Up( x, y, z ); tgtView->SetUp( x, y, z );
224 refView->Eye( x, y, z ); tgtView->SetEye( x, y, z );
225 refView->Proj( x, y, z ); tgtView->SetProj( x, y, z );
226 refView->Center( x, y ); tgtView->SetCenter( x, y );
227 tgtView->SetScale( refView->Scale() );
228 tgtView->SetTwist( refView->Twist() );
232 tgtView->SetImmediateUpdate( Standard_True );
237 Returns Z-size of this view. [ public ]
239 double OCCViewer_ViewPort3d::getZSize() const
241 if ( !activeView().IsNull() )
242 return activeView()->ZSize();
247 Sets Z-size of this view ( for both orthographic and perspective ). [ public ]
249 void OCCViewer_ViewPort3d::setZSize( double zsize )
251 myActiveView->SetZSize( zsize );
252 /* if ( !myOrthoView.IsNull() )
253 myOrthoView->SetZSize( zsize );
254 if ( !myPerspView.IsNull() )
255 myPerspView->SetZSize( zsize );*/
259 Get axial scale to the view
261 void OCCViewer_ViewPort3d::getAxialScale( double& xScale, double& yScale, double& zScale )
263 xScale = yScale = zScale = 1.;
265 if ( !activeView().IsNull() )
266 activeView()->AxialScale( xScale, yScale, zScale );
270 Returns the background color [ virtual public ] [ obsolete ]
272 QColor OCCViewer_ViewPort3d::backgroundColor() const
274 return background().color();
278 Sets the background color [ virtual public ] [ obsolete ]
280 void OCCViewer_ViewPort3d::setBackgroundColor( const QColor& color )
282 Qtx::BackgroundData bg = background();
283 bg.setColor( color );
288 Returns the background data
290 Qtx::BackgroundData OCCViewer_ViewPort3d::background() const
296 Sets the background data
298 void OCCViewer_ViewPort3d::setBackground( const Qtx::BackgroundData& bgData )
300 if ( bgData.isValid() ) {
301 myBackground = bgData;
303 emit vpChangeBackground( myBackground );
307 void OCCViewer_ViewPort3d::updateBackground()
309 if ( activeView().IsNull() ) return;
310 if ( !myBackground.isValid() ) return;
312 // VSR: Important note on below code.
313 // In OCCT (in version 6.5.2), things about the background drawing
314 // are not straightforward and not clearly understandable:
315 // - Horizontal gradient is drawn vertically (!), well ok, from top side to bottom one.
316 // - Vertical gradient is drawn horizontally (!), from right side to left one (!!!).
317 // - First and second diagonal gradients are confused.
318 // - Image texture, once set, can not be removed (!).
319 // - Texture image fill mode Aspect_FM_NONE is not taken into account (and means the same
320 // as Aspect_FM_CENTERED).
321 // - The only way to cancel gradient background (and get back to single colored) is to
322 // set gradient background style to Aspect_GFM_NONE while passing two colors is also needed
323 // (see V3d_View::SetBgGradientColors() function).
324 // - Also, it is impossible to draw texture image above the gradiented background (only above
326 // In OCCT 6.5.3 all above mentioned problems are fixed; so, above comment should be removed as soon
327 // as SALOME is migrated to OCCT 6.5.3. The same concerns #ifdef statements in the below code
328 switch ( myBackground.mode() ) {
329 case Qtx::ColorBackground:
331 QColor c = myBackground.color();
333 // Unset texture should be done here
335 Quantity_Color qCol( c.red()/255., c.green()/255., c.blue()/255., Quantity_TOC_RGB );
336 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
337 activeView()->SetBgGradientStyle( Aspect_GFM_NONE ); // cancel gradient background
338 activeView()->SetBgImageStyle( Aspect_FM_NONE ); // cancel texture background
340 // cancel gradient background (in OCC before v6.5.3 the only way to do this is to set it to NONE type passing arbitrary colors as parameters)
341 activeView()->SetBgGradientColors( qCol, qCol, Aspect_GFM_NONE );
343 // then change background color
344 activeView()->SetBackgroundColor( qCol );
346 activeView()->Update();
350 case Qtx::SimpleGradientBackground:
353 int type = myBackground.gradient( c1, c2 );
354 if ( c1.isValid() && type >= OCCViewer_Viewer::HorizontalGradient && type <= OCCViewer_Viewer::LastGradient ) {
355 // Unset texture should be done here
357 // Get colors and set-up gradiented background
358 if ( !c2.isValid() ) c2 = c1;
359 Quantity_Color qCol1( c1.red()/255., c1.green()/255., c1.blue()/255., Quantity_TOC_RGB );
360 Quantity_Color qCol2( c2.red()/255., c2.green()/255., c2.blue()/255., Quantity_TOC_RGB );
361 activeView()->SetBgImageStyle( Aspect_FM_NONE ); // cancel texture background
363 case OCCViewer_Viewer::HorizontalGradient:
364 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
365 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_HOR, Standard_True );
367 // in OCCT before v6.5.3, to draw horizontal gradient it's necessary to use Aspect_GFM_VER type
368 // and interchange the colors
369 activeView()->SetBgGradientColors( qCol2, qCol1, Aspect_GFM_VER, Standard_True );
372 case OCCViewer_Viewer::VerticalGradient:
373 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
374 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_VER, Standard_True );
376 // in OCCT before v6.5.3, to draw vertical gradient it's necessary to use Aspect_GFM_HOR type
377 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_HOR, Standard_True );
380 case OCCViewer_Viewer::Diagonal1Gradient:
381 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
382 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_DIAG1, Standard_True );
384 // in OCCT before v6.5.3, to draw 1st dialognal gradient it's necessary to use Aspect_GFM_DIAG2 type
385 // and interchange the colors
386 activeView()->SetBgGradientColors( qCol2, qCol1, Aspect_GFM_DIAG2, Standard_True );
389 case OCCViewer_Viewer::Diagonal2Gradient:
390 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
391 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_DIAG2, Standard_True );
393 // in OCCT before v6.5.3, to draw 2nd dialognal gradient it's necessary to use Aspect_GFM_DIAG1 type
394 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_DIAG1, Standard_True );
397 case OCCViewer_Viewer::Corner1Gradient:
398 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER1, Standard_True );
400 case OCCViewer_Viewer::Corner2Gradient:
401 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER2, Standard_True );
403 case OCCViewer_Viewer::Corner3Gradient:
404 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER3, Standard_True );
406 case OCCViewer_Viewer::Corner4Gradient:
407 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER4, Standard_True );
415 case Qtx::CustomGradientBackground:
417 // NOT IMPLEMENTED YET
423 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
424 // VSR: In OCCT before v6.5.3 below code can't be used because of very ugly bug - it has been impossible to
425 // clear the background texture image as soon as it was once set to the viewer.
426 if ( myBackground.isTextureShown() ) {
428 int textureMode = myBackground.texture( fileName );
429 QFileInfo fi( fileName );
430 if ( !fileName.isEmpty() && fi.exists() ) {
431 // set texture image: file name and fill mode
432 switch ( textureMode ) {
433 case Qtx::CenterTexture:
434 activeView()->SetBackgroundImage( fi.absoluteFilePath().toLatin1().constData(), Aspect_FM_CENTERED );
436 case Qtx::TileTexture:
437 activeView()->SetBackgroundImage( fi.absoluteFilePath().toLatin1().constData(), Aspect_FM_TILED );
439 case Qtx::StretchTexture:
440 activeView()->SetBackgroundImage( fi.absoluteFilePath().toLatin1().constData(), Aspect_FM_STRETCH );
445 activeView()->Update();
452 Updates the active viewport. [ virtual public ]
454 void OCCViewer_ViewPort3d::onUpdate()
456 if ( !activeView().IsNull() )
457 activeView()->Update();
461 Called at 'window fit' transformation. [ virtual protected ]
463 void OCCViewer_ViewPort3d::fitRect( const QRect& rect )
465 if ( !activeView().IsNull() ) {
466 activeView()->WindowFit( rect.left(), rect.top(), rect.right(), rect.bottom() );
467 emit vpTransformed( this );
472 Inits 'zoom' transformation. [ protected ]
474 void OCCViewer_ViewPort3d::startZoomAtPoint( int x, int y )
476 #if OCC_VERSION_LARGE > 0x0603000A // available only with OCC-6.3-sp11 and higher version
477 if ( !activeView().IsNull() && isAdvancedZoomingEnabled() )
478 activeView()->StartZoomAtPoint( x, y );
483 Called at 'zoom' transformation. [ virtual protected ]
485 void OCCViewer_ViewPort3d::zoom( int x0, int y0, int x, int y )
487 if ( !activeView().IsNull() ) {
488 // as OCCT respects a sign of only dx,
489 // but we want both signes to be taken into account
490 //activeView()->Zoom( x0, y0, x, y );
491 #if OCC_VERSION_LARGE > 0x0603000A // available only with OCC-6.3-sp11 and higher version
492 if ( isAdvancedZoomingEnabled() )
493 activeView()->ZoomAtPoint( x0, y0, x, y );
496 activeView()->Zoom( x0 + y0, 0, x + y, 0 );
497 emit vpTransformed( this );
502 Centers the viewport. [ virtual protected ]
504 void OCCViewer_ViewPort3d::setCenter( int x, int y )
506 if ( !activeView().IsNull() ) {
507 activeView()->Place( x, y, myScale );
508 emit vpTransformed( this );
513 Called at 'pan' transformation. [ virtual protected ]
515 void OCCViewer_ViewPort3d::pan( int dx, int dy )
517 if ( !activeView().IsNull() ) {
518 activeView()->Pan( dx, dy, 1.0 );
519 emit vpTransformed( this );
524 Inits 'rotation' transformation. [ protected ]
526 void OCCViewer_ViewPort3d::startRotation( int x, int y,
527 int theRotationPointType,
528 const gp_Pnt& theSelectedPoint )
530 if ( !activeView().IsNull() ) {
532 //double gx = activeView()->gx;
533 //activeView()->Gravity(gx,gy,gz);
535 switch ( theRotationPointType ) {
536 case OCCViewer_ViewWindow::GRAVITY:
537 activeView()->StartRotation( x, y, 0.45 );
539 case OCCViewer_ViewWindow::SELECTED:
543 activeView()->Size(X,Y);
544 rx = Standard_Real(activeView()->Convert(X));
545 ry = Standard_Real(activeView()->Convert(Y));
547 activeView()->Rotate( 0., 0., 0.,
548 theSelectedPoint.X(),theSelectedPoint.Y(), theSelectedPoint.Z(),
551 Quantity_Ratio zRotationThreshold;
552 zRotation = Standard_False;
553 zRotationThreshold = 0.45;
554 if( zRotationThreshold > 0. ) {
555 Standard_Real dx = Abs(sx - rx/2.);
556 Standard_Real dy = Abs(sy - ry/2.);
557 Standard_Real dd = zRotationThreshold * (rx + ry)/2.;
558 if( dx > dd || dy > dd ) zRotation = Standard_True;
564 activeView()->DepthFitAll();
569 Rotates the viewport. [ protected ]
571 void OCCViewer_ViewPort3d::rotate( int x, int y,
572 int theRotationPointType,
573 const gp_Pnt& theSelectedPoint )
575 if ( !activeView().IsNull() ) {
576 switch ( theRotationPointType ) {
577 case OCCViewer_ViewWindow::GRAVITY:
578 activeView()->Rotation( x, y );
580 case OCCViewer_ViewWindow::SELECTED:
583 dz = atan2(Standard_Real(x)-rx/2., ry/2.-Standard_Real(y)) -
584 atan2(sx-rx/2.,ry/2.-sy);
588 dx = (Standard_Real(x) - sx) * M_PI/rx;
589 dy = (sy - Standard_Real(y)) * M_PI/ry;
593 activeView()->Rotate( dx, dy, dz,
594 theSelectedPoint.X(),theSelectedPoint.Y(), theSelectedPoint.Z(),
600 emit vpTransformed( this );
602 // setZSize( getZSize() );
606 Resets the viewport after 'rotation'. [ protected ]
608 void OCCViewer_ViewPort3d::endRotation()
610 if ( !activeView().IsNull() ) {
611 activeView()->ZFitAll(1.);
612 activeView()->SetZSize(0.);
613 activeView()->Update();
614 emit vpTransformed( this );
619 Repaints the viewport. [ virtual protected ]
621 void OCCViewer_ViewPort3d::paintEvent( QPaintEvent* e )
624 /* X11 : map before show doesn't work */
625 if ( !mapped( activeView() ) )
626 mapView( activeView() );
628 if ( !myWindow.IsNull() ) {
629 QApplication::syncX();
630 QRect rc = e->rect();
631 if ( !myPaintersRedrawing )
632 activeView()->Redraw( rc.x(), rc.y(), rc.width(), rc.height() );
634 OCCViewer_ViewPort::paintEvent( e );
639 Resizes the viewport. [ virtual protected ]
641 void OCCViewer_ViewPort3d::resizeEvent( QResizeEvent* e )
644 /* Win32 : map before first show to avoid flicker */
645 if ( !mapped( activeView() ) )
646 mapView( activeView() );
648 QApplication::syncX();
649 if ( !activeView().IsNull() )
650 activeView()->MustBeResized();
654 Fits all objects in view. [ virtual protected ]
656 void OCCViewer_ViewPort3d::fitAll( bool keepScale, bool withZ, bool upd )
658 if ( activeView().IsNull() )
662 myScale = activeView()->Scale();
664 Standard_Real margin = 0.01;
665 activeView()->FitAll( margin, withZ, upd );
666 activeView()->SetZSize(0.);
667 emit vpTransformed( this );
671 Resets the view. [ virtual protected ]
673 void OCCViewer_ViewPort3d::reset()
675 // double zsize = getZSize();
676 if ( !activeView().IsNull() ) {
677 activeView()->Reset();
678 emit vpTransformed( this );
679 // setZSize( zsize );
684 Rotate the view in the view plane (orthogonal to the view vector)
686 void OCCViewer_ViewPort3d::rotateXY( double degrees )
688 if ( activeView().IsNull() )
691 int x = width()/2, y = height()/2;
693 activeView()->Convert( x, y, X, Y, Z );
694 activeView()->Rotate( 0, 0, degrees * M_PI / 180., X, Y, Z );
695 emit vpTransformed( this );
699 Set axial scale to the view
701 void OCCViewer_ViewPort3d::setAxialScale( double xScale, double yScale, double zScale )
703 if ( activeView().IsNull() )
706 activeView()->SetAxialScale( xScale, yScale, zScale );
707 emit vpTransformed( this );
711 Passed the handle of native window of the component to CASCADE view. [ private ]
713 bool OCCViewer_ViewPort3d::setWindow( const Handle(V3d_View)& view )
715 if ( !myWindow.IsNull() )
721 attachWindow( view, OCCViewer_VService::CreateWindow( view, winId() ) );
723 myWindow = view->Window();
724 return !myWindow.IsNull();
727 void OCCViewer_ViewPort3d::attachWindow( const Handle(V3d_View)& view,
728 const Handle(Aspect_Window)& window)
730 if (!view.IsNull()) {
731 view->SetWindow( window );
737 Returns the current active view. [ private ]
739 Handle(V3d_View) OCCViewer_ViewPort3d::activeView() const
745 Returns the current inactive view [ private ]
747 /*Handle(V3d_View) OCCViewer_ViewPort3d::inactiveView() const
749 return ( activeView() == myOrthoView ? myPerspView : myOrthoView );
753 Returns 'true' if the given view is mapped to window. [ private ]
755 bool OCCViewer_ViewPort3d::mapped( const Handle(V3d_View)& view ) const
757 return ( !view.IsNull() && view->View()->IsDefined() );
761 Performs synchronization of view parameters with the specified view.
762 Returns \c true if synchronization is done successfully or \c false otherwise.
763 Default implementation does nothing (return \c false)
765 bool OCCViewer_ViewPort3d::synchronize( OCCViewer_ViewPort* view )
768 OCCViewer_ViewPort3d* vp3d = qobject_cast<OCCViewer_ViewPort3d*>( view );
770 bool blocked = blockSignals( false );
771 Handle(V3d_View) aView3d = getView();
772 Handle(V3d_View) aRefView3d = vp3d->getView();
773 aView3d->SetImmediateUpdate( Standard_False );
774 aView3d->SetViewMapping( aRefView3d->ViewMapping() );
775 aView3d->SetViewOrientation( aRefView3d->ViewOrientation() );
777 aView3d->SetImmediateUpdate( Standard_True );
779 blockSignals( blocked );
786 * Show/Hide static triedron
788 void OCCViewer_ViewPort3d::updateStaticTriedronVisibility() {
789 OCCViewer_ViewWindow* aVW = dynamic_cast<OCCViewer_ViewWindow*>( parentWidget()->parentWidget()->parentWidget() );
791 OCCViewer_Viewer* aViewModel = dynamic_cast<OCCViewer_Viewer*>( aVW->getViewManager()->getViewModel() );
792 Handle(V3d_View) aView = activeView();
794 if(aViewModel->isStaticTrihedronDisplayed()) {
795 aView->TriedronDisplay( Aspect_TOTP_LEFT_LOWER, Quantity_NOC_WHITE, 0.05, V3d_ZBUFFER );
797 aView->TriedronErase();