1 // Copyright (C) 2007-2014 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, or (at your option) any later version.
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 <SUIT_ViewManager.h>
30 #include <SUIT_ViewModel.h>
36 #include <QPaintEvent>
37 #include <QResizeEvent>
38 #include <QApplication>
40 #include <Visual3d_View.hxx>
41 #include <V3d_Viewer.hxx>
43 #if OCC_VERSION_LARGE > 0x06070100
44 #include <V3d_View.hxx>
46 #include <V3d_PerspectiveView.hxx>
47 #include <V3d_OrthographicView.hxx>
50 #include "utilities.h"
53 #include <WNT_Window.hxx>
55 #include <Xw_Window.hxx>
58 static double rx = 0.;
59 static double ry = 0.;
62 static Standard_Boolean zRotation = Standard_False;
64 //#include <Standard_Version.hxx>
69 OCCViewer_ViewPort3d::OCCViewer_ViewPort3d( QWidget* parent, const Handle( V3d_Viewer)& viewer, V3d_TypeOfView type )
70 : OCCViewer_ViewPort( parent ),
73 myIsAdvancedZoomingEnabled( false )
75 // VSR: 01/07/2010 commented to avoid SIGSEGV at SALOME exit
78 #if OCC_VERSION_LARGE > 0x06070100
79 myActiveView = new V3d_View( viewer, type );
81 if ( type == V3d_ORTHOGRAPHIC ) {
82 myOrthoView = new V3d_OrthographicView( viewer );
83 myActiveView = myOrthoView;
86 myPerspView = new V3d_PerspectiveView( viewer );
87 myActiveView = myPerspView;
91 setBackground( Qtx::BackgroundData( Qt::black ) ); // set default background
97 OCCViewer_ViewPort3d::~OCCViewer_ViewPort3d()
100 Handle(V3d_View) aView = activeView();
106 Activates the desired 'type' of view in the viewer
107 ( view of 'type' is created if it doesn't exist ). [ public ]
109 /*void OCCViewer_ViewPort3d::setActive( V3d_TypeOfView type )
111 if ( activeView().IsNull() )
114 if ( activeView()->Type() != type )
116 if ( type == V3d_ORTHOGRAPHIC )
117 setView( myOrthoView );
118 if ( type == V3d_PERSPECTIVE )
119 setView( myPerspView );
124 Maps CasCade 'view' to this viewport. [ private ]
126 bool OCCViewer_ViewPort3d::mapView( const Handle(V3d_View)& view )
128 if ( !setWindow( view ) )
131 if ( !mapped( view ) ) {
132 view->SetWindow( myWindow );
133 if ( view != activeView() )
134 view->View()->Deactivate();
137 emit( vpMapped(this) );
145 Sets new CASCADE view on viewport. Returns the previous active view. [ public ]
147 Handle( V3d_View ) OCCViewer_ViewPort3d::setView( const Handle( V3d_View )& view )
149 /* map the new view */
150 if ( view == activeView() || !mapView( view ) )
153 /* activate the new view*/
154 Handle( V3d_View ) oldView = activeView();
155 if ( !oldView.IsNull() ) {
156 if (oldView->View()->IsDefined())
157 oldView->View()->Deactivate();
158 view->SetBackgroundColor( oldView->BackgroundColor() );
161 view->View()->Activate();
167 Returns CasCade 3D view. [ public ]
169 Handle(V3d_View) OCCViewer_ViewPort3d::getView() const
175 Returns CasCade 3D viewer [ public ]
177 Handle(V3d_Viewer) OCCViewer_ViewPort3d::getViewer() const
179 Handle(V3d_Viewer) viewer;
180 if ( !activeView().IsNull() )
181 viewer = activeView()->Viewer();
186 Syncronizes visual state of this viewport with 'ref'
187 ( scale, projection, eye etc ) Returns 'true' if copied OK,
188 'false' otherwise. [ virtual public ]
190 bool OCCViewer_ViewPort3d::syncronize( const OCCViewer_ViewPort3d* ref )
192 OCCViewer_ViewPort3d* ref3d = (OCCViewer_ViewPort3d*)ref;
193 Handle(V3d_View) refView = ref3d->getView();
194 Handle(V3d_View) tgtView = getView();
196 /* Syncronize view types */
197 /* if ( tgtView->Type() != refView->Type() )
199 setActive( refView->Type() );
203 /* The following params are copied:
204 - view type( ortho/persp )
205 - position of view point
206 - orientation of high point
207 - position of the eye
214 /* we'll update after setting all params */
215 tgtView->SetImmediateUpdate( Standard_False );
218 if ( refView->Type() == V3d_PERSPECTIVE )
219 tgtView->SetFocale( refView->Focale() );
222 Standard_Real x, y, z;
223 refView->At( x, y, z ); tgtView->SetAt( x, y, z );
224 refView->Up( x, y, z ); tgtView->SetUp( x, y, z );
225 refView->Eye( x, y, z ); tgtView->SetEye( x, y, z );
226 refView->Proj( x, y, z ); tgtView->SetProj( x, y, z );
227 #if OCC_VERSION_LARGE <= 0x06070100
228 refView->Center( x, y ); tgtView->SetCenter( x, y );
230 tgtView->SetScale( refView->Scale() );
231 tgtView->SetTwist( refView->Twist() );
235 tgtView->SetImmediateUpdate( Standard_True );
241 Returns Z-size of this view. [ public ]
243 double OCCViewer_ViewPort3d::getZSize() const
245 if ( !activeView().IsNull() )
246 return activeView()->ZSize();
251 Sets Z-size of this view ( for both orthographic and perspective ). [ public ]
253 void OCCViewer_ViewPort3d::setZSize( double zsize )
255 myActiveView->SetZSize( zsize );
256 /* if ( !myOrthoView.IsNull() )
257 myOrthoView->SetZSize( zsize );
258 if ( !myPerspView.IsNull() )
259 myPerspView->SetZSize( zsize );*/
263 Get axial scale to the view
265 void OCCViewer_ViewPort3d::getAxialScale( double& xScale, double& yScale, double& zScale )
267 xScale = yScale = zScale = 1.;
269 if ( !activeView().IsNull() )
270 activeView()->AxialScale( xScale, yScale, zScale );
274 Returns the background color [ virtual public ] [ obsolete ]
276 QColor OCCViewer_ViewPort3d::backgroundColor() const
278 return background().color();
282 Sets the background color [ virtual public ] [ obsolete ]
284 void OCCViewer_ViewPort3d::setBackgroundColor( const QColor& color )
286 Qtx::BackgroundData bg = background();
287 bg.setColor( color );
292 Returns the background data
294 Qtx::BackgroundData OCCViewer_ViewPort3d::background() const
300 Sets the background data
302 void OCCViewer_ViewPort3d::setBackground( const Qtx::BackgroundData& bgData )
304 if ( bgData.isValid() ) {
305 myBackground = bgData;
307 emit vpChangeBackground( myBackground );
311 void OCCViewer_ViewPort3d::updateBackground()
313 if ( activeView().IsNull() ) return;
314 if ( !myBackground.isValid() ) return;
316 // VSR: Important note on below code.
317 // In OCCT (in version 6.5.2), things about the background drawing
318 // are not straightforward and not clearly understandable:
319 // - Horizontal gradient is drawn vertically (!), well ok, from top side to bottom one.
320 // - Vertical gradient is drawn horizontally (!), from right side to left one (!!!).
321 // - First and second diagonal gradients are confused.
322 // - Image texture, once set, can not be removed (!).
323 // - Texture image fill mode Aspect_FM_NONE is not taken into account (and means the same
324 // as Aspect_FM_CENTERED).
325 // - The only way to cancel gradient background (and get back to single colored) is to
326 // set gradient background style to Aspect_GFM_NONE while passing two colors is also needed
327 // (see V3d_View::SetBgGradientColors() function).
328 // - Also, it is impossible to draw texture image above the gradiented background (only above
330 // In OCCT 6.5.3 all above mentioned problems are fixed; so, above comment should be removed as soon
331 // as SALOME is migrated to OCCT 6.5.3. The same concerns #ifdef statements in the below code
332 switch ( myBackground.mode() ) {
333 case Qtx::ColorBackground:
335 QColor c = myBackground.color();
337 // Unset texture should be done here
339 Quantity_Color qCol( c.red()/255., c.green()/255., c.blue()/255., Quantity_TOC_RGB );
340 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
341 activeView()->SetBgGradientStyle( Aspect_GFM_NONE ); // cancel gradient background
342 activeView()->SetBgImageStyle( Aspect_FM_NONE ); // cancel texture background
344 // 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)
345 activeView()->SetBgGradientColors( qCol, qCol, Aspect_GFM_NONE );
347 // then change background color
348 activeView()->SetBackgroundColor( qCol );
350 activeView()->Update();
354 case Qtx::SimpleGradientBackground:
357 int type = myBackground.gradient( c1, c2 );
358 if ( c1.isValid() && type >= OCCViewer_Viewer::HorizontalGradient && type <= OCCViewer_Viewer::LastGradient ) {
359 // Unset texture should be done here
361 // Get colors and set-up gradiented background
362 if ( !c2.isValid() ) c2 = c1;
363 Quantity_Color qCol1( c1.red()/255., c1.green()/255., c1.blue()/255., Quantity_TOC_RGB );
364 Quantity_Color qCol2( c2.red()/255., c2.green()/255., c2.blue()/255., Quantity_TOC_RGB );
365 activeView()->SetBgImageStyle( Aspect_FM_NONE ); // cancel texture background
367 case OCCViewer_Viewer::HorizontalGradient:
368 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
369 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_HOR, Standard_True );
371 // in OCCT before v6.5.3, to draw horizontal gradient it's necessary to use Aspect_GFM_VER type
372 // and interchange the colors
373 activeView()->SetBgGradientColors( qCol2, qCol1, Aspect_GFM_VER, Standard_True );
376 case OCCViewer_Viewer::VerticalGradient:
377 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
378 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_VER, Standard_True );
380 // in OCCT before v6.5.3, to draw vertical gradient it's necessary to use Aspect_GFM_HOR type
381 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_HOR, Standard_True );
384 case OCCViewer_Viewer::Diagonal1Gradient:
385 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
386 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_DIAG1, Standard_True );
388 // in OCCT before v6.5.3, to draw 1st dialognal gradient it's necessary to use Aspect_GFM_DIAG2 type
389 // and interchange the colors
390 activeView()->SetBgGradientColors( qCol2, qCol1, Aspect_GFM_DIAG2, Standard_True );
393 case OCCViewer_Viewer::Diagonal2Gradient:
394 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
395 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_DIAG2, Standard_True );
397 // in OCCT before v6.5.3, to draw 2nd dialognal gradient it's necessary to use Aspect_GFM_DIAG1 type
398 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_DIAG1, Standard_True );
401 case OCCViewer_Viewer::Corner1Gradient:
402 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER1, Standard_True );
404 case OCCViewer_Viewer::Corner2Gradient:
405 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER2, Standard_True );
407 case OCCViewer_Viewer::Corner3Gradient:
408 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER3, Standard_True );
410 case OCCViewer_Viewer::Corner4Gradient:
411 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER4, Standard_True );
419 case Qtx::CustomGradientBackground:
421 // NOT IMPLEMENTED YET
427 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
428 // VSR: In OCCT before v6.5.3 below code can't be used because of very ugly bug - it has been impossible to
429 // clear the background texture image as soon as it was once set to the viewer.
430 if ( myBackground.isTextureShown() ) {
432 int textureMode = myBackground.texture( fileName );
433 QFileInfo fi( fileName );
434 if ( !fileName.isEmpty() && fi.exists() ) {
435 // set texture image: file name and fill mode
436 switch ( textureMode ) {
437 case Qtx::CenterTexture:
438 activeView()->SetBackgroundImage( fi.absoluteFilePath().toLatin1().constData(), Aspect_FM_CENTERED );
440 case Qtx::TileTexture:
441 activeView()->SetBackgroundImage( fi.absoluteFilePath().toLatin1().constData(), Aspect_FM_TILED );
443 case Qtx::StretchTexture:
444 activeView()->SetBackgroundImage( fi.absoluteFilePath().toLatin1().constData(), Aspect_FM_STRETCH );
449 activeView()->Update();
456 Updates the active viewport. [ virtual public ]
458 void OCCViewer_ViewPort3d::onUpdate()
460 if ( !activeView().IsNull() )
461 activeView()->Update();
465 Called at 'window fit' transformation. [ virtual protected ]
467 void OCCViewer_ViewPort3d::fitRect( const QRect& rect )
469 if ( !activeView().IsNull() ) {
470 activeView()->WindowFit( rect.left(), rect.top(), rect.right(), rect.bottom() );
471 emit vpTransformed( this );
476 Inits 'zoom' transformation. [ protected ]
478 void OCCViewer_ViewPort3d::startZoomAtPoint( int x, int y )
480 #if OCC_VERSION_LARGE > 0x0603000A // available only with OCC-6.3-sp11 and higher version
481 if ( !activeView().IsNull() && isAdvancedZoomingEnabled() )
482 activeView()->StartZoomAtPoint( x, y );
487 Called at 'zoom' transformation. [ virtual protected ]
489 void OCCViewer_ViewPort3d::zoom( int x0, int y0, int x, int y )
491 if ( !activeView().IsNull() ) {
492 // as OCCT respects a sign of only dx,
493 // but we want both signes to be taken into account
494 //activeView()->Zoom( x0, y0, x, y );
495 #if OCC_VERSION_LARGE > 0x0603000A // available only with OCC-6.3-sp11 and higher version
496 if ( isAdvancedZoomingEnabled() )
497 activeView()->ZoomAtPoint( x0, y0, x, y );
500 activeView()->Zoom( x0 + y0, 0, x + y, 0 );
501 emit vpTransformed( this );
506 Centers the viewport. [ virtual protected ]
508 void OCCViewer_ViewPort3d::setCenter( int x, int y )
510 if ( !activeView().IsNull() ) {
511 activeView()->Place( x, y, myScale );
512 emit vpTransformed( this );
517 Called at 'pan' transformation. [ virtual protected ]
519 void OCCViewer_ViewPort3d::pan( int dx, int dy )
521 if ( !activeView().IsNull() ) {
522 activeView()->Pan( dx, dy, 1.0 );
523 emit vpTransformed( this );
528 Inits 'rotation' transformation. [ protected ]
530 void OCCViewer_ViewPort3d::startRotation( int x, int y,
531 int theRotationPointType,
532 const gp_Pnt& theSelectedPoint )
534 if ( !activeView().IsNull() ) {
536 //double gx = activeView()->gx;
537 //activeView()->Gravity(gx,gy,gz);
539 switch ( theRotationPointType ) {
540 case OCCViewer_ViewWindow::GRAVITY:
541 activeView()->StartRotation( x, y, 0.45 );
543 case OCCViewer_ViewWindow::SELECTED:
547 activeView()->Size(X,Y);
548 rx = Standard_Real(activeView()->Convert(X));
549 ry = Standard_Real(activeView()->Convert(Y));
551 activeView()->Rotate( 0., 0., 0.,
552 theSelectedPoint.X(),theSelectedPoint.Y(), theSelectedPoint.Z(),
555 Quantity_Ratio zRotationThreshold;
556 zRotation = Standard_False;
557 zRotationThreshold = 0.45;
558 if( zRotationThreshold > 0. ) {
559 Standard_Real dx = Abs(sx - rx/2.);
560 Standard_Real dy = Abs(sy - ry/2.);
561 Standard_Real dd = zRotationThreshold * (rx + ry)/2.;
562 if( dx > dd || dy > dd ) zRotation = Standard_True;
568 activeView()->DepthFitAll();
573 Rotates the viewport. [ protected ]
575 void OCCViewer_ViewPort3d::rotate( int x, int y,
576 int theRotationPointType,
577 const gp_Pnt& theSelectedPoint )
579 if ( !activeView().IsNull() ) {
580 switch ( theRotationPointType ) {
581 case OCCViewer_ViewWindow::GRAVITY:
582 activeView()->Rotation( x, y );
584 case OCCViewer_ViewWindow::SELECTED:
587 dz = atan2(Standard_Real(x)-rx/2., ry/2.-Standard_Real(y)) -
588 atan2(sx-rx/2.,ry/2.-sy);
592 dx = (Standard_Real(x) - sx) * M_PI/rx;
593 dy = (sy - Standard_Real(y)) * M_PI/ry;
597 activeView()->Rotate( dx, dy, dz,
598 theSelectedPoint.X(),theSelectedPoint.Y(), theSelectedPoint.Z(),
604 emit vpTransformed( this );
606 // setZSize( getZSize() );
610 Resets the viewport after 'rotation'. [ protected ]
612 void OCCViewer_ViewPort3d::endRotation()
614 if ( !activeView().IsNull() ) {
615 activeView()->ZFitAll( 1.0 );
616 #if OCC_VERSION_LARGE <= 0x06070100
617 activeView()->SetZSize( 0.0 );
619 activeView()->Update();
620 emit vpTransformed( this );
625 Repaints the viewport. [ virtual protected ]
627 void OCCViewer_ViewPort3d::paintEvent( QPaintEvent* e )
630 /* X11 : map before show doesn't work */
631 if ( !mapped( activeView() ) )
632 mapView( activeView() );
634 if ( !myWindow.IsNull() ) {
635 QApplication::syncX();
636 QRect rc = e->rect();
637 if ( !myPaintersRedrawing )
638 activeView()->Redraw( rc.x(), rc.y(), rc.width(), rc.height() );
640 OCCViewer_ViewPort::paintEvent( e );
645 Resizes the viewport. [ virtual protected ]
647 void OCCViewer_ViewPort3d::resizeEvent( QResizeEvent* e )
650 /* Win32 : map before first show to avoid flicker */
651 if ( !mapped( activeView() ) )
652 mapView( activeView() );
654 QApplication::syncX();
655 if ( !activeView().IsNull() )
656 activeView()->MustBeResized();
660 Fits all objects in view. [ virtual protected ]
662 void OCCViewer_ViewPort3d::fitAll( bool keepScale, bool withZ, bool upd )
664 if ( activeView().IsNull() )
668 myScale = activeView()->Scale();
670 Standard_Real margin = 0.01;
672 #if OCC_VERSION_LARGE > 0x06070100
673 activeView()->FitAll( margin, upd );
675 activeView()->ZFitAll();
677 activeView()->FitAll( margin, withZ, upd );
679 activeView()->SetZSize(0.);
680 emit vpTransformed( this );
684 Resets the view. [ virtual protected ]
686 void OCCViewer_ViewPort3d::reset()
688 // double zsize = getZSize();
689 if ( !activeView().IsNull() ) {
690 activeView()->Reset();
691 emit vpTransformed( this );
692 // setZSize( zsize );
697 Rotate the view in the view plane (orthogonal to the view vector)
699 void OCCViewer_ViewPort3d::rotateXY( double degrees )
701 if ( activeView().IsNull() )
704 int x = width()/2, y = height()/2;
706 activeView()->Convert( x, y, X, Y, Z );
707 activeView()->Rotate( 0, 0, degrees * M_PI / 180., X, Y, Z );
708 emit vpTransformed( this );
712 Set axial scale to the view
714 void OCCViewer_ViewPort3d::setAxialScale( double xScale, double yScale, double zScale )
716 if ( activeView().IsNull() )
719 activeView()->SetAxialScale( xScale, yScale, zScale );
720 emit vpTransformed( this );
724 Passed the handle of native window of the component to CASCADE view. [ private ]
726 bool OCCViewer_ViewPort3d::setWindow( const Handle(V3d_View)& view )
728 if ( !myWindow.IsNull() )
734 attachWindow( view, OCCViewer_VService::CreateWindow( view, winId() ) );
736 myWindow = view->Window();
737 return !myWindow.IsNull();
740 void OCCViewer_ViewPort3d::attachWindow( const Handle(V3d_View)& view,
741 const Handle(Aspect_Window)& window)
743 if (!view.IsNull()) {
744 view->SetWindow( window );
750 Returns the current active view. [ private ]
752 Handle(V3d_View) OCCViewer_ViewPort3d::activeView() const
758 Returns the current inactive view [ private ]
760 /*Handle(V3d_View) OCCViewer_ViewPort3d::inactiveView() const
762 return ( activeView() == myOrthoView ? myPerspView : myOrthoView );
766 Returns 'true' if the given view is mapped to window. [ private ]
768 bool OCCViewer_ViewPort3d::mapped( const Handle(V3d_View)& view ) const
770 return ( !view.IsNull() && view->View()->IsDefined() );
774 Performs synchronization of view parameters with the specified view.
775 Returns \c true if synchronization is done successfully or \c false otherwise.
776 Default implementation does nothing (return \c false)
778 bool OCCViewer_ViewPort3d::synchronize( OCCViewer_ViewPort* view )
781 OCCViewer_ViewPort3d* vp3d = qobject_cast<OCCViewer_ViewPort3d*>( view );
783 bool blocked = blockSignals( false );
784 Handle(V3d_View) aView3d = getView();
785 Handle(V3d_View) aRefView3d = vp3d->getView();
786 aView3d->SetImmediateUpdate( Standard_False );
787 #if OCC_VERSION_LARGE > 0x06070100
788 aView3d->Camera()->Copy( aRefView3d->Camera() );
790 aView3d->SetViewMapping( aRefView3d->ViewMapping() );
791 aView3d->SetViewOrientation( aRefView3d->ViewOrientation() );
794 aView3d->SetImmediateUpdate( Standard_True );
796 blockSignals( blocked );
803 * Show/Hide static triedron
805 void OCCViewer_ViewPort3d::showStaticTrihedron( bool on )
807 Handle(V3d_View) aView = activeView();
808 if ( !aView ) return;
811 aView->ZBufferTriedronSetup();
812 aView->TriedronDisplay( Aspect_TOTP_LEFT_LOWER, Quantity_NOC_WHITE, 0.05, V3d_ZBUFFER );
814 aView->TriedronErase();