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 );
147 Sets new CASCADE view on viewport. Returns the previous active view. [ public ]
149 Handle( V3d_View ) OCCViewer_ViewPort3d::setView( const Handle( V3d_View )& view )
151 /* map the new view */
152 if ( view == activeView() || !mapView( view ) )
155 /* activate the new view*/
156 Handle( V3d_View ) oldView = activeView();
157 if ( !oldView.IsNull() ) {
158 if (oldView->View()->IsDefined())
159 oldView->View()->Deactivate();
160 view->SetBackgroundColor( oldView->BackgroundColor() );
163 view->View()->Activate();
169 Returns CasCade 3D view. [ public ]
171 Handle(V3d_View) OCCViewer_ViewPort3d::getView() const
177 Returns CasCade 3D viewer [ public ]
179 Handle(V3d_Viewer) OCCViewer_ViewPort3d::getViewer() const
181 Handle(V3d_Viewer) viewer;
182 if ( !activeView().IsNull() )
183 viewer = activeView()->Viewer();
188 Syncronizes visual state of this viewport with 'ref'
189 ( scale, projection, eye etc ) Returns 'true' if copied OK,
190 'false' otherwise. [ virtual public ]
192 bool OCCViewer_ViewPort3d::syncronize( const OCCViewer_ViewPort3d* ref )
194 OCCViewer_ViewPort3d* ref3d = (OCCViewer_ViewPort3d*)ref;
195 Handle(V3d_View) refView = ref3d->getView();
196 Handle(V3d_View) tgtView = getView();
198 /* Syncronize view types */
199 /* if ( tgtView->Type() != refView->Type() )
201 setActive( refView->Type() );
205 /* The following params are copied:
206 - view type( ortho/persp )
207 - position of view point
208 - orientation of high point
209 - position of the eye
216 /* we'll update after setting all params */
217 tgtView->SetImmediateUpdate( Standard_False );
220 if ( refView->Type() == V3d_PERSPECTIVE )
221 tgtView->SetFocale( refView->Focale() );
224 Standard_Real x, y, z;
225 refView->At( x, y, z ); tgtView->SetAt( x, y, z );
226 refView->Up( x, y, z ); tgtView->SetUp( x, y, z );
227 refView->Eye( x, y, z ); tgtView->SetEye( x, y, z );
228 refView->Proj( x, y, z ); tgtView->SetProj( x, y, z );
229 refView->Center( x, y ); tgtView->SetCenter( x, y );
230 tgtView->SetScale( refView->Scale() );
231 tgtView->SetTwist( refView->Twist() );
235 tgtView->SetImmediateUpdate( Standard_True );
240 Returns Z-size of this view. [ public ]
242 double OCCViewer_ViewPort3d::getZSize() const
244 if ( !activeView().IsNull() )
245 return activeView()->ZSize();
250 Sets Z-size of this view ( for both orthographic and perspective ). [ public ]
252 void OCCViewer_ViewPort3d::setZSize( double zsize )
254 myActiveView->SetZSize( zsize );
255 /* if ( !myOrthoView.IsNull() )
256 myOrthoView->SetZSize( zsize );
257 if ( !myPerspView.IsNull() )
258 myPerspView->SetZSize( zsize );*/
262 Get axial scale to the view
264 void OCCViewer_ViewPort3d::getAxialScale( double& xScale, double& yScale, double& zScale )
266 xScale = yScale = zScale = 1.;
268 if ( !activeView().IsNull() )
269 activeView()->AxialScale( xScale, yScale, zScale );
273 Returns the background color [ virtual public ] [ obsolete ]
275 QColor OCCViewer_ViewPort3d::backgroundColor() const
277 return background().color();
281 Sets the background color [ virtual public ] [ obsolete ]
283 void OCCViewer_ViewPort3d::setBackgroundColor( const QColor& color )
285 Qtx::BackgroundData bg = background();
286 bg.setColor( color );
291 Returns the background data
293 Qtx::BackgroundData OCCViewer_ViewPort3d::background() const
299 Sets the background data
301 void OCCViewer_ViewPort3d::setBackground( const Qtx::BackgroundData& bgData )
303 if ( bgData.isValid() ) {
304 myBackground = bgData;
306 emit vpChangeBackground( myBackground );
310 void OCCViewer_ViewPort3d::updateBackground()
312 if ( activeView().IsNull() ) return;
313 if ( !myBackground.isValid() ) return;
315 // VSR: Important note on below code.
316 // In OCCT (in version 6.5.2), things about the background drawing
317 // are not straightforward and not clearly understandable:
318 // - Horizontal gradient is drawn vertically (!), well ok, from top side to bottom one.
319 // - Vertical gradient is drawn horizontally (!), from right side to left one (!!!).
320 // - First and second diagonal gradients are confused.
321 // - Image texture, once set, can not be removed (!).
322 // - Texture image fill mode Aspect_FM_NONE is not taken into account (and means the same
323 // as Aspect_FM_CENTERED).
324 // - The only way to cancel gradient background (and get back to single colored) is to
325 // set gradient background style to Aspect_GFM_NONE while passing two colors is also needed
326 // (see V3d_View::SetBgGradientColors() function).
327 // - Also, it is impossible to draw texture image above the gradiented background (only above
329 // In OCCT 6.5.3 all above mentioned problems are fixed; so, above comment should be removed as soon
330 // as SALOME is migrated to OCCT 6.5.3. The same concerns #ifdef statements in the below code
331 switch ( myBackground.mode() ) {
332 case Qtx::ColorBackground:
334 QColor c = myBackground.color();
336 // Unset texture should be done here
338 Quantity_Color qCol( c.red()/255., c.green()/255., c.blue()/255., Quantity_TOC_RGB );
339 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
340 activeView()->SetBgGradientStyle( Aspect_GFM_NONE ); // cancel gradient background
341 activeView()->SetBgImageStyle( Aspect_FM_NONE ); // cancel texture background
343 // 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)
344 activeView()->SetBgGradientColors( qCol, qCol, Aspect_GFM_NONE );
346 // then change background color
347 activeView()->SetBackgroundColor( qCol );
349 activeView()->Update();
353 case Qtx::SimpleGradientBackground:
356 int type = myBackground.gradient( c1, c2 );
357 if ( c1.isValid() && type >= OCCViewer_Viewer::HorizontalGradient && type <= OCCViewer_Viewer::LastGradient ) {
358 // Unset texture should be done here
360 // Get colors and set-up gradiented background
361 if ( !c2.isValid() ) c2 = c1;
362 Quantity_Color qCol1( c1.red()/255., c1.green()/255., c1.blue()/255., Quantity_TOC_RGB );
363 Quantity_Color qCol2( c2.red()/255., c2.green()/255., c2.blue()/255., Quantity_TOC_RGB );
364 activeView()->SetBgImageStyle( Aspect_FM_NONE ); // cancel texture background
366 case OCCViewer_Viewer::HorizontalGradient:
367 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
368 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_HOR, Standard_True );
370 // in OCCT before v6.5.3, to draw horizontal gradient it's necessary to use Aspect_GFM_VER type
371 // and interchange the colors
372 activeView()->SetBgGradientColors( qCol2, qCol1, Aspect_GFM_VER, Standard_True );
375 case OCCViewer_Viewer::VerticalGradient:
376 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
377 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_VER, Standard_True );
379 // in OCCT before v6.5.3, to draw vertical gradient it's necessary to use Aspect_GFM_HOR type
380 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_HOR, Standard_True );
383 case OCCViewer_Viewer::Diagonal1Gradient:
384 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
385 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_DIAG1, Standard_True );
387 // in OCCT before v6.5.3, to draw 1st dialognal gradient it's necessary to use Aspect_GFM_DIAG2 type
388 // and interchange the colors
389 activeView()->SetBgGradientColors( qCol2, qCol1, Aspect_GFM_DIAG2, Standard_True );
392 case OCCViewer_Viewer::Diagonal2Gradient:
393 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
394 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_DIAG2, Standard_True );
396 // in OCCT before v6.5.3, to draw 2nd dialognal gradient it's necessary to use Aspect_GFM_DIAG1 type
397 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_DIAG1, Standard_True );
400 case OCCViewer_Viewer::Corner1Gradient:
401 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER1, Standard_True );
403 case OCCViewer_Viewer::Corner2Gradient:
404 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER2, Standard_True );
406 case OCCViewer_Viewer::Corner3Gradient:
407 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER3, Standard_True );
409 case OCCViewer_Viewer::Corner4Gradient:
410 activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER4, Standard_True );
418 case Qtx::CustomGradientBackground:
420 // NOT IMPLEMENTED YET
426 #if OCC_VERSION_LARGE > 0x06050200 // available since OCCT 6.5.3
427 // VSR: In OCCT before v6.5.3 below code can't be used because of very ugly bug - it has been impossible to
428 // clear the background texture image as soon as it was once set to the viewer.
429 if ( myBackground.isTextureShown() ) {
431 int textureMode = myBackground.texture( fileName );
432 QFileInfo fi( fileName );
433 if ( !fileName.isEmpty() && fi.exists() ) {
434 // set texture image: file name and fill mode
435 switch ( textureMode ) {
436 case Qtx::CenterTexture:
437 activeView()->SetBackgroundImage( fi.absoluteFilePath().toLatin1().constData(), Aspect_FM_CENTERED );
439 case Qtx::TileTexture:
440 activeView()->SetBackgroundImage( fi.absoluteFilePath().toLatin1().constData(), Aspect_FM_TILED );
442 case Qtx::StretchTexture:
443 activeView()->SetBackgroundImage( fi.absoluteFilePath().toLatin1().constData(), Aspect_FM_STRETCH );
448 activeView()->Update();
455 Updates the active viewport. [ virtual public ]
457 void OCCViewer_ViewPort3d::onUpdate()
459 if ( !activeView().IsNull() )
460 activeView()->Update();
464 Called at 'window fit' transformation. [ virtual protected ]
466 void OCCViewer_ViewPort3d::fitRect( const QRect& rect )
468 if ( !activeView().IsNull() ) {
469 activeView()->WindowFit( rect.left(), rect.top(), rect.right(), rect.bottom() );
470 emit vpTransformed( this );
475 Inits 'zoom' transformation. [ protected ]
477 void OCCViewer_ViewPort3d::startZoomAtPoint( int x, int y )
479 #if OCC_VERSION_LARGE > 0x0603000A // available only with OCC-6.3-sp11 and higher version
480 if ( !activeView().IsNull() && isAdvancedZoomingEnabled() )
481 activeView()->StartZoomAtPoint( x, y );
486 Called at 'zoom' transformation. [ virtual protected ]
488 void OCCViewer_ViewPort3d::zoom( int x0, int y0, int x, int y )
490 if ( !activeView().IsNull() ) {
491 // as OCCT respects a sign of only dx,
492 // but we want both signes to be taken into account
493 //activeView()->Zoom( x0, y0, x, y );
494 #if OCC_VERSION_LARGE > 0x0603000A // available only with OCC-6.3-sp11 and higher version
495 if ( isAdvancedZoomingEnabled() )
496 activeView()->ZoomAtPoint( x0, y0, x, y );
499 activeView()->Zoom( x0 + y0, 0, x + y, 0 );
500 emit vpTransformed( this );
505 Centers the viewport. [ virtual protected ]
507 void OCCViewer_ViewPort3d::setCenter( int x, int y )
509 if ( !activeView().IsNull() ) {
510 activeView()->Place( x, y, myScale );
511 emit vpTransformed( this );
516 Called at 'pan' transformation. [ virtual protected ]
518 void OCCViewer_ViewPort3d::pan( int dx, int dy )
520 if ( !activeView().IsNull() ) {
521 activeView()->Pan( dx, dy, 1.0 );
522 emit vpTransformed( this );
527 Inits 'rotation' transformation. [ protected ]
529 void OCCViewer_ViewPort3d::startRotation( int x, int y,
530 int theRotationPointType,
531 const gp_Pnt& theSelectedPoint )
533 if ( !activeView().IsNull() ) {
535 //double gx = activeView()->gx;
536 //activeView()->Gravity(gx,gy,gz);
538 switch ( theRotationPointType ) {
539 case OCCViewer_ViewWindow::GRAVITY:
540 activeView()->StartRotation( x, y, 0.45 );
542 case OCCViewer_ViewWindow::SELECTED:
546 activeView()->Size(X,Y);
547 rx = Standard_Real(activeView()->Convert(X));
548 ry = Standard_Real(activeView()->Convert(Y));
550 activeView()->Rotate( 0., 0., 0.,
551 theSelectedPoint.X(),theSelectedPoint.Y(), theSelectedPoint.Z(),
554 Quantity_Ratio zRotationThreshold;
555 zRotation = Standard_False;
556 zRotationThreshold = 0.45;
557 if( zRotationThreshold > 0. ) {
558 Standard_Real dx = Abs(sx - rx/2.);
559 Standard_Real dy = Abs(sy - ry/2.);
560 Standard_Real dd = zRotationThreshold * (rx + ry)/2.;
561 if( dx > dd || dy > dd ) zRotation = Standard_True;
567 activeView()->DepthFitAll();
572 Rotates the viewport. [ protected ]
574 void OCCViewer_ViewPort3d::rotate( int x, int y,
575 int theRotationPointType,
576 const gp_Pnt& theSelectedPoint )
578 if ( !activeView().IsNull() ) {
579 switch ( theRotationPointType ) {
580 case OCCViewer_ViewWindow::GRAVITY:
581 activeView()->Rotation( x, y );
583 case OCCViewer_ViewWindow::SELECTED:
586 dz = atan2(Standard_Real(x)-rx/2., ry/2.-Standard_Real(y)) -
587 atan2(sx-rx/2.,ry/2.-sy);
591 dx = (Standard_Real(x) - sx) * M_PI/rx;
592 dy = (sy - Standard_Real(y)) * M_PI/ry;
596 activeView()->Rotate( dx, dy, dz,
597 theSelectedPoint.X(),theSelectedPoint.Y(), theSelectedPoint.Z(),
603 emit vpTransformed( this );
605 // setZSize( getZSize() );
609 Resets the viewport after 'rotation'. [ protected ]
611 void OCCViewer_ViewPort3d::endRotation()
613 if ( !activeView().IsNull() ) {
614 activeView()->ZFitAll(1.);
615 activeView()->SetZSize(0.);
616 activeView()->Update();
617 emit vpTransformed( this );
622 Repaints the viewport. [ virtual protected ]
624 void OCCViewer_ViewPort3d::paintEvent( QPaintEvent* e )
627 /* X11 : map before show doesn't work */
628 if ( !mapped( activeView() ) )
629 mapView( activeView() );
631 if ( !myWindow.IsNull() ) {
632 QApplication::syncX();
633 QRect rc = e->rect();
634 if ( !myPaintersRedrawing )
635 activeView()->Redraw( rc.x(), rc.y(), rc.width(), rc.height() );
637 OCCViewer_ViewPort::paintEvent( e );
642 Resizes the viewport. [ virtual protected ]
644 void OCCViewer_ViewPort3d::resizeEvent( QResizeEvent* e )
647 /* Win32 : map before first show to avoid flicker */
648 if ( !mapped( activeView() ) )
649 mapView( activeView() );
651 QApplication::syncX();
652 if ( !activeView().IsNull() )
653 activeView()->MustBeResized();
657 Fits all objects in view. [ virtual protected ]
659 void OCCViewer_ViewPort3d::fitAll( bool keepScale, bool withZ, bool upd )
661 if ( activeView().IsNull() )
665 myScale = activeView()->Scale();
667 Standard_Real margin = 0.01;
668 activeView()->FitAll( margin, withZ, upd );
669 activeView()->SetZSize(0.);
670 emit vpTransformed( this );
674 Resets the view. [ virtual protected ]
676 void OCCViewer_ViewPort3d::reset()
678 // double zsize = getZSize();
679 if ( !activeView().IsNull() ) {
680 activeView()->Reset();
681 emit vpTransformed( this );
682 // setZSize( zsize );
687 Rotate the view in the view plane (orthogonal to the view vector)
689 void OCCViewer_ViewPort3d::rotateXY( double degrees )
691 if ( activeView().IsNull() )
694 int x = width()/2, y = height()/2;
696 activeView()->Convert( x, y, X, Y, Z );
697 activeView()->Rotate( 0, 0, degrees * M_PI / 180., X, Y, Z );
698 emit vpTransformed( this );
702 Set axial scale to the view
704 void OCCViewer_ViewPort3d::setAxialScale( double xScale, double yScale, double zScale )
706 if ( activeView().IsNull() )
709 activeView()->SetAxialScale( xScale, yScale, zScale );
710 emit vpTransformed( this );
714 Passed the handle of native window of the component to CASCADE view. [ private ]
716 bool OCCViewer_ViewPort3d::setWindow( const Handle(V3d_View)& view )
718 if ( !myWindow.IsNull() )
724 attachWindow( view, OCCViewer_VService::CreateWindow( view, winId() ) );
726 myWindow = view->Window();
727 return !myWindow.IsNull();
730 void OCCViewer_ViewPort3d::attachWindow( const Handle(V3d_View)& view,
731 const Handle(Aspect_Window)& window)
733 if (!view.IsNull()) {
734 view->SetWindow( window );
740 Returns the current active view. [ private ]
742 Handle(V3d_View) OCCViewer_ViewPort3d::activeView() const
748 Returns the current inactive view [ private ]
750 /*Handle(V3d_View) OCCViewer_ViewPort3d::inactiveView() const
752 return ( activeView() == myOrthoView ? myPerspView : myOrthoView );
756 Returns 'true' if the given view is mapped to window. [ private ]
758 bool OCCViewer_ViewPort3d::mapped( const Handle(V3d_View)& view ) const
760 return ( !view.IsNull() && view->View()->IsDefined() );
764 Performs synchronization of view parameters with the specified view.
765 Returns \c true if synchronization is done successfully or \c false otherwise.
766 Default implementation does nothing (return \c false)
768 bool OCCViewer_ViewPort3d::synchronize( OCCViewer_ViewPort* view )
771 OCCViewer_ViewPort3d* vp3d = qobject_cast<OCCViewer_ViewPort3d*>( view );
773 bool blocked = blockSignals( false );
774 Handle(V3d_View) aView3d = getView();
775 Handle(V3d_View) aRefView3d = vp3d->getView();
776 aView3d->SetImmediateUpdate( Standard_False );
777 aView3d->SetViewMapping( aRefView3d->ViewMapping() );
778 aView3d->SetViewOrientation( aRefView3d->ViewOrientation() );
780 aView3d->SetImmediateUpdate( Standard_True );
782 blockSignals( blocked );
789 * Show/Hide static triedron
791 void OCCViewer_ViewPort3d::updateStaticTriedronVisibility() {
792 OCCViewer_ViewWindow* aVW = dynamic_cast<OCCViewer_ViewWindow*>( parentWidget()->parentWidget()->parentWidget() );
794 OCCViewer_Viewer* aViewModel = dynamic_cast<OCCViewer_Viewer*>( aVW->getViewManager()->getViewModel() );
795 Handle(V3d_View) aView = activeView();
797 if(aViewModel->isStaticTrihedronDisplayed()) {
798 aView->TriedronDisplay( Aspect_TOTP_LEFT_LOWER, Quantity_NOC_WHITE, 0.05, V3d_ZBUFFER );
800 aView->TriedronErase();