View3DInventorViewer.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2004 Jürgen Riegel <juergen.riegel@web.de>              *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 
00026 #ifndef _PreComp_
00027 # include <float.h>
00028 # ifdef FC_OS_WIN32
00029 #  include <windows.h>
00030 # endif
00031 # ifdef FC_OS_MACOSX
00032 # include <OpenGL/gl.h>
00033 # else
00034 # include <GL/gl.h>
00035 # endif
00036 # include <Inventor/SbBox.h>
00037 # include <Inventor/actions/SoGetBoundingBoxAction.h>
00038 # include <Inventor/actions/SoHandleEventAction.h> 
00039 # include <Inventor/actions/SoToVRML2Action.h>
00040 # include <Inventor/actions/SoWriteAction.h>
00041 # include <Inventor/manips/SoClipPlaneManip.h>
00042 # include <Inventor/nodes/SoBaseColor.h>
00043 # include <Inventor/nodes/SoCallback.h> 
00044 # include <Inventor/nodes/SoCoordinate3.h>
00045 # include <Inventor/nodes/SoCube.h>
00046 # include <Inventor/nodes/SoDirectionalLight.h>
00047 # include <Inventor/nodes/SoEventCallback.h>
00048 # include <Inventor/nodes/SoFaceSet.h>
00049 # include <Inventor/nodes/SoImage.h>
00050 # include <Inventor/nodes/SoIndexedFaceSet.h>
00051 # include <Inventor/nodes/SoLightModel.h>
00052 # include <Inventor/nodes/SoLocateHighlight.h>
00053 # include <Inventor/nodes/SoMaterial.h>
00054 # include <Inventor/nodes/SoMaterialBinding.h>
00055 # include <Inventor/nodes/SoOrthographicCamera.h>
00056 # include <Inventor/nodes/SoPerspectiveCamera.h>
00057 # include <Inventor/nodes/SoRotationXYZ.h>
00058 # include <Inventor/nodes/SoSeparator.h>
00059 # include <Inventor/nodes/SoShapeHints.h>
00060 # include <Inventor/nodes/SoSwitch.h>
00061 # include <Inventor/nodes/SoTransform.h>
00062 # include <Inventor/nodes/SoTranslation.h>
00063 # include <Inventor/nodes/SoSelection.h>
00064 # include <Inventor/actions/SoBoxHighlightRenderAction.h>
00065 # include <Inventor/events/SoEvent.h>
00066 # include <Inventor/events/SoKeyboardEvent.h>
00067 # include <Inventor/events/SoLocation2Event.h>
00068 # include <Inventor/events/SoMotion3Event.h>
00069 # include <Inventor/events/SoMouseButtonEvent.h>
00070 # include <Inventor/actions/SoRayPickAction.h>
00071 # include <Inventor/projectors/SbSphereSheetProjector.h>
00072 # include <Inventor/SoOffscreenRenderer.h>
00073 # include <Inventor/SoPickedPoint.h>
00074 # include <Inventor/VRMLnodes/SoVRMLGroup.h>
00075 # include <QEventLoop>
00076 # include <QKeyEvent>
00077 # include <QMessageBox>
00078 # include <QTimer>
00079 # include <QStatusBar>
00080 #endif
00081 
00082 #include <sstream>
00083 #include <Base/Console.h>
00084 #include <Base/Stream.h>
00085 #include <Base/FileInfo.h>
00086 #include <Base/Sequencer.h>
00087 #include <Base/Tools.h>
00088 #include <zipios++/gzipoutputstream.h>
00089 
00090 #include "View3DInventorViewer.h"
00091 #include "ViewProviderDocumentObject.h"
00092 #include "SoFCBackgroundGradient.h"
00093 #include "SoFCColorBar.h"
00094 #include "SoFCColorLegend.h"
00095 #include "SoFCColorGradient.h"
00096 #include "SoFCOffscreenRenderer.h"
00097 #include "SoFCSelection.h"
00098 #include "SoFCUnifiedSelection.h"
00099 #include "SoFCInteractiveElement.h"
00100 #include "SoFCBoundingBox.h"
00101 #include "Selection.h"
00102 #include "SoFCSelectionAction.h"
00103 #include "SoFCVectorizeU3DAction.h"
00104 #include "SoFCVectorizeSVGAction.h"
00105 #include "SoFCDB.h"
00106 #include "MainWindow.h"
00107 #include "NavigationStyle.h"
00108 #include "ViewProvider.h"
00109 #include "SpaceballEvent.h"
00110 
00111 #include <Inventor/draggers/SoCenterballDragger.h>
00112 
00113 
00114 //#define FC_LOGGING_CB
00115 
00116 #define new DEBUG_CLIENTBLOCK
00117 
00118 using namespace Gui;
00119 
00130 // *************************************************************************
00131 
00132 SOQT_OBJECT_ABSTRACT_SOURCE(View3DInventorViewer);
00133 
00134 // *************************************************************************
00135 
00136 View3DInventorViewer::View3DInventorViewer (QWidget *parent, const char *name, 
00137                                             SbBool embed, Type type, SbBool build) 
00138   : inherited (parent, name, embed, type, build), editViewProvider(0),navigation(0),
00139     editing(FALSE), redirected(FALSE)
00140 {
00141     Gui::Selection().Attach(this);
00142 
00143     // Coin should not clear the pixel-buffer, so the background image
00144     // is not removed.
00145     this->setClearBeforeRender(FALSE);
00146 
00147     // setting up the defaults for the spin rotation
00148     initialize();
00149 
00150     SoOrthographicCamera * cam = new SoOrthographicCamera;
00151     cam->position = SbVec3f(0, 0, 1);
00152     cam->height = 1;
00153     cam->nearDistance = 0.5;
00154     cam->farDistance = 1.5;
00155 
00156     // setup light sources
00157     SoDirectionalLight *hl = this->getHeadlight();
00158     backlight = new SoDirectionalLight();
00159     backlight->ref();
00160     backlight->setName("soqt->backlight");
00161     backlight->direction.setValue(-hl->direction.getValue());
00162     backlight->on.setValue(FALSE); // by default off
00163 
00164     // Set up background scenegraph with image in it.
00165     backgroundroot = new SoSeparator;
00166     backgroundroot->ref();
00167     this->backgroundroot->addChild(cam);
00168 
00169     // Background stuff
00170     pcBackGround = new SoFCBackgroundGradient;
00171     pcBackGround->ref();
00172 
00173     // Set up foreground, overlayed scenegraph.
00174     this->foregroundroot = new SoSeparator;
00175     this->foregroundroot->ref();
00176 
00177     SoLightModel * lm = new SoLightModel;
00178     lm->model = SoLightModel::BASE_COLOR;
00179 
00180     SoBaseColor * bc = new SoBaseColor;
00181     bc->rgb = SbColor(1, 1, 0);
00182 
00183     cam = new SoOrthographicCamera;
00184     cam->position = SbVec3f(0, 0, 5);
00185     cam->height = 10;
00186     cam->nearDistance = 0;
00187     cam->farDistance = 10;
00188 
00189     // dragger
00190     //SoSeparator * dragSep = new SoSeparator();
00191     //SoScale *scale = new SoScale();
00192     //scale->scaleFactor = SbVec3f  (0.2,0.2,0.2);
00193     //dragSep->addChild(scale);
00194     //SoCenterballDragger *dragger = new SoCenterballDragger();
00195     //dragger->center = SbVec3f  (0.8,0.8,0);
00197     //dragSep->addChild(dragger);
00198 
00199     this->foregroundroot->addChild(cam);
00200     this->foregroundroot->addChild(lm);
00201     this->foregroundroot->addChild(bc);
00202     //this->foregroundroot->addChild(dragSep);
00203 
00204 #if 0
00205     // NOTE: For every mouse click event the SoSelection searches for the picked
00206     // point which causes a certain slow-down because for all objects the primitives
00207     // must be created. Using an SoSeparator avoids this drawback.
00208     SoSelection* selectionRoot = new SoSelection();
00209     selectionRoot->addSelectionCallback(View3DInventorViewer::selectCB, this);
00210     selectionRoot->addDeselectionCallback(View3DInventorViewer::deselectCB, this);
00211     selectionRoot->setPickFilterCallback(View3DInventorViewer::pickFilterCB, this);
00212 #else
00213     // NOTE: For every mouse click event the SoFCUnifiedSelection searches for the picked
00214     // point which causes a certain slow-down because for all objects the primitives
00215     // must be created. Using an SoSeparator avoids this drawback.
00216     Gui::SoFCUnifiedSelection* selectionRoot = new Gui::SoFCUnifiedSelection();
00217     selectionRoot->applySettings();
00218     selectionRoot->viewer = this;
00219 #endif
00220     // set the ViewProvider root node
00221     pcViewProviderRoot = selectionRoot;
00222 
00223     // increase refcount before passing it to setScenegraph(), to avoid
00224     // premature destruction
00225     pcViewProviderRoot->ref();
00226     // is not really working with Coin3D. 
00227     //redrawOverlayOnSelectionChange(pcSelection);
00228     setSceneGraph(pcViewProviderRoot);
00229     // Event callback node
00230     pEventCallback = new SoEventCallback();
00231     pEventCallback->setUserData(this);
00232     pEventCallback->ref();
00233     pcViewProviderRoot->addChild(pEventCallback);
00234     pEventCallback->addEventCallback(SoEvent::getClassTypeId(), handleEventCB, this);
00235 
00236     // This is a callback node that logs all action that traverse the Inventor tree.
00237 #if defined (FC_DEBUG) && defined(FC_LOGGING_CB)
00238     SoCallback * cb = new SoCallback;           
00239     cb->setCallback(interactionLoggerCB, this);
00240     pcViewProviderRoot->addChild(cb);
00241 #endif
00242 
00243     // Set our own render action which show a bounding box if
00244     // the SoFCSelection::BOX style is set
00245     this->setGLRenderAction(new SoBoxSelectionRenderAction);
00246 
00247     // set the transperency and antialiasing settings
00248 //  getGLRenderAction()->setTransparencyType(SoGLRenderAction::SORTED_OBJECT_BLEND);
00249     getGLRenderAction()->setTransparencyType(SoGLRenderAction::SORTED_OBJECT_SORTED_TRIANGLE_BLEND);
00250 //  getGLRenderAction()->setSmoothing(true);
00251 
00252     // Settings
00253     setSeekTime(0.4f);
00254     if (isSeekValuePercentage() == false)
00255         setSeekValueAsPercentage(true);
00256     setSeekDistance(100);
00257     setViewing(false);
00258 
00259     setBackgroundColor(SbColor(0.1f, 0.1f, 0.1f));
00260     setGradientBackgroud(true);
00261 
00262     // set some callback functions for user interaction
00263     addStartCallback(interactionStartCB);
00264     addFinishCallback(interactionFinishCB);
00265 }
00266 
00267 View3DInventorViewer::~View3DInventorViewer()
00268 {
00269     // cleanup
00270     this->backgroundroot->unref();
00271     this->backgroundroot = 0;
00272     this->foregroundroot->unref();
00273     this->foregroundroot = 0;
00274     this->pcBackGround->unref();
00275     this->pcBackGround = 0;
00276 
00277     setSceneGraph(0);
00278     this->pEventCallback->unref();
00279     this->pEventCallback = 0;
00280     this->pcViewProviderRoot->unref();
00281     this->pcViewProviderRoot = 0;
00282     this->backlight->unref();
00283     this->backlight = 0;
00284 
00285     delete this->navigation;
00286 
00287     // Note: When closing the application the main window doesn't exist any more.
00288     if (getMainWindow())
00289         getMainWindow()->setPaneText(2, QLatin1String(""));
00290     Gui::Selection().Detach(this);
00291 }
00292 
00293 void View3DInventorViewer::initialize()
00294 {
00295     navigation = new CADNavigationStyle();
00296     navigation->setViewer(this);
00297 
00298     this->axiscrossEnabled = TRUE;
00299     this->axiscrossSize = 10;
00300 }
00301 
00303 void View3DInventorViewer::OnChange(Gui::SelectionSingleton::SubjectType &rCaller,
00304                                     Gui::SelectionSingleton::MessageType Reason)
00305 {
00306     if (Reason.Type == SelectionChanges::AddSelection ||
00307         Reason.Type == SelectionChanges::RmvSelection ||
00308         Reason.Type == SelectionChanges::SetSelection ||
00309         Reason.Type == SelectionChanges::ClrSelection) {
00310         SoFCSelectionAction cAct(Reason);
00311         cAct.apply(pcViewProviderRoot);
00312     }
00313 }
00315 
00316 SbBool View3DInventorViewer::hasViewProvider(ViewProvider* pcProvider) const
00317 {
00318     return _ViewProviderSet.find(pcProvider) != _ViewProviderSet.end();
00319 }
00320 
00322 void View3DInventorViewer::addViewProvider(ViewProvider* pcProvider)
00323 {
00324     SoSeparator* root = pcProvider->getRoot();
00325     if (root){
00326         pcViewProviderRoot->addChild(root);
00327         _ViewProviderMap[root] = pcProvider;
00328     }
00329     SoSeparator* fore = pcProvider->getFrontRoot();
00330     if (fore) foregroundroot->addChild(fore);
00331     SoSeparator* back = pcProvider->getBackRoot ();
00332     if (back) backgroundroot->addChild(back);
00333 
00334     _ViewProviderSet.insert(pcProvider);
00335 }
00336 
00337 void View3DInventorViewer::removeViewProvider(ViewProvider* pcProvider)
00338 {
00339     if (this->editViewProvider == pcProvider)
00340         resetEditingViewProvider();
00341 
00342     SoSeparator* root = pcProvider->getRoot();
00343     if (root){
00344         pcViewProviderRoot->removeChild(root);
00345         _ViewProviderMap.erase(root);
00346     }
00347     SoSeparator* fore = pcProvider->getFrontRoot();
00348     if (fore) foregroundroot->removeChild(fore);
00349     SoSeparator* back = pcProvider->getBackRoot ();
00350     if (back) backgroundroot->removeChild(back);
00351   
00352     _ViewProviderSet.erase(pcProvider);
00353   
00354 }
00355 
00356 SbBool View3DInventorViewer::setEditingViewProvider(Gui::ViewProvider* p, int ModNum)
00357 {
00358     if (_ViewProviderSet.find(p) == _ViewProviderSet.end())
00359         return false;
00360     if (this->editViewProvider)
00361         return false; // only one view provider is editable at a time
00362     bool ok = p->startEditing(ModNum);
00363     if (ok) {
00364         this->editViewProvider = p;
00365         this->editViewProvider->setEditViewer(this, ModNum);
00366         addEventCallback(SoEvent::getClassTypeId(), Gui::ViewProvider::eventCallback,this->editViewProvider);
00367     }
00368 
00369     return ok;
00370 }
00371 
00373 void View3DInventorViewer::resetEditingViewProvider()
00374 {
00375     if (this->editViewProvider) {
00376         this->editViewProvider->unsetEditViewer(this);
00377         this->editViewProvider->finishEditing();
00378         removeEventCallback(SoEvent::getClassTypeId(), Gui::ViewProvider::eventCallback,this->editViewProvider);
00379         this->editViewProvider = 0;
00380     }
00381 }
00382 
00384 SbBool View3DInventorViewer::isEditingViewProvider() const
00385 {
00386     return this->editViewProvider ? true : false;
00387 }
00388 
00389 void View3DInventorViewer::clearBuffer(void * userdata, SoAction * action)
00390 {
00391     if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
00392         // do stuff specific for GL rendering here.
00393         glClear(GL_DEPTH_BUFFER_BIT);
00394     }
00395 }
00396 
00397 void View3DInventorViewer::setGLWidget(void * userdata, SoAction * action)
00398 {
00399     //FIXME: This causes the Coin error message:
00400     // Coin error in SoNode::GLRenderS(): GL error: 'GL_STACK_UNDERFLOW', nodetype:
00401     // Separator (set envvar COIN_GLERROR_DEBUGGING=1 and re-run to get more information)
00402     if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
00403         QWidget* gl = reinterpret_cast<QWidget*>(userdata);
00404         SoGLWidgetElement::set(action->getState(), qobject_cast<QGLWidget*>(gl));
00405     }
00406 }
00407 
00408 void View3DInventorViewer::handleEventCB(void * ud, SoEventCallback * n)
00409 {
00410     View3DInventorViewer* that = reinterpret_cast<View3DInventorViewer*>(ud);
00411     SoGLRenderAction * glra = that->getGLRenderAction();
00412     SoAction* action = n->getAction();
00413     SoGLRenderActionElement::set(action->getState(), glra);
00414     SoGLWidgetElement::set(action->getState(), qobject_cast<QGLWidget*>(that->getGLWidget()));
00415 }
00416 
00417 void View3DInventorViewer::setGradientBackgroud(bool on)
00418 {
00419     if (on && backgroundroot->findChild(pcBackGround) == -1)
00420         backgroundroot->addChild(pcBackGround);
00421     else if (!on && backgroundroot->findChild(pcBackGround) != -1)
00422         backgroundroot->removeChild(pcBackGround);
00423 }
00424 
00425 void View3DInventorViewer::setGradientBackgroudColor(const SbColor& fromColor,
00426                                                      const SbColor& toColor)
00427 {
00428     pcBackGround->setColorGradient(fromColor, toColor);
00429 }
00430 
00431 void View3DInventorViewer::setGradientBackgroudColor(const SbColor& fromColor,
00432                                                      const SbColor& toColor,
00433                                                      const SbColor& midColor)
00434 {
00435     pcBackGround->setColorGradient(fromColor, toColor, midColor);
00436 }
00437 
00438 void View3DInventorViewer::setEnabledFPSCounter(bool on)
00439 {
00440 #if defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
00441     setenv("COIN_SHOW_FPS_COUNTER", (on?"1":"0"), 1);
00442 #else
00443     on ? _putenv ("COIN_SHOW_FPS_COUNTER=1") : _putenv ("COIN_SHOW_FPS_COUNTER=0");
00444 #endif
00445 }
00446 
00447 void View3DInventorViewer::setNavigationType(Base::Type t)
00448 {
00449     if (t.isBad())
00450         return;
00451     if (this->navigation && this->navigation->getTypeId() == t)
00452         return; // nothing to do
00453     Base::BaseClass* base = static_cast<Base::BaseClass*>(t.createInstance());
00454     if (!base)
00455         return;
00456     if (!base->getTypeId().isDerivedFrom(NavigationStyle::getClassTypeId())) {
00457         delete base;
00458 #if SOQT_DEBUG
00459         SoDebugError::postWarning("View3DInventorViewer::setNavigationType",
00460                                   "Navigation object must be of type NavigationStyle.");
00461 #endif // SO@GUI_DEBUG 
00462         return;
00463     }
00464 
00465     NavigationStyle* ns = static_cast<NavigationStyle*>(base);
00466     ns->operator = (*this->navigation);
00467     delete this->navigation;
00468     this->navigation = ns;
00469     this->navigation->setViewer(this);
00470 }
00471 
00472 NavigationStyle* View3DInventorViewer::navigationStyle() const
00473 {
00474     return this->navigation;
00475 }
00476 
00477 SoDirectionalLight* View3DInventorViewer::getBacklight(void) const
00478 {
00479     return this->backlight;
00480 }
00481 
00482 void View3DInventorViewer::setBacklight(SbBool on)
00483 {
00484     this->backlight->on = on;
00485 }
00486 
00487 SbBool View3DInventorViewer::isBacklight(void) const
00488 {
00489     return this->backlight->on.getValue();
00490 }
00491 
00492 void View3DInventorViewer::setSceneGraph (SoNode *root)
00493 {
00494     inherited::setSceneGraph(root);
00495 
00496     SoSearchAction sa;
00497     sa.setNode(this->backlight);
00498     SoNode* scene = this->getSceneManager()->getSceneGraph();
00499     if (scene && scene->getTypeId().isDerivedFrom(SoSeparator::getClassTypeId())) {
00500         sa.apply(scene);
00501         if (!sa.getPath())
00502             static_cast<SoSeparator*>(scene)->insertChild(this->backlight, 1);
00503     }
00504 }
00505 
00506 void View3DInventorViewer::savePicture(const char* filename, int w, int h,
00507                                        int eBackgroundType, const char* comment) const
00508 {
00509     // if no valid color use the current background
00510     bool useBackground = false;
00511     SbViewportRegion vp(getViewportRegion());
00512     if (w>0 && h>0)
00513         vp.setWindowSize( (short)w, (short)h );
00514 
00515     //NOTE: To support pixels per inch we must use SbViewportRegion::setPixelsPerInch( ppi );
00516     //The default value is 72.0.
00517     //If we need to support grayscale images with must either use SoOffscreenRenderer::LUMINANCE or 
00518     //SoOffscreenRenderer::LUMINANCE_TRANSPARENCY. 
00519     SoFCOffscreenRenderer& renderer = SoFCOffscreenRenderer::instance();
00520     renderer.setViewportRegion(vp);
00521     SoCallback* cb = 0;
00522 
00523     // if we use transparency then we must not set a background color
00524     switch(eBackgroundType){
00525         case Current:
00526             useBackground = true;
00527             cb = new SoCallback;
00528             cb->setCallback(clearBuffer);
00529             break;
00530         case White:
00531             renderer.setBackgroundColor( SbColor(1.0, 1.0, 1.0) );
00532             break;
00533         case Black:
00534             renderer.setBackgroundColor( SbColor(0.0, 0.0, 0.0) );
00535             break;
00536         case Transparent:
00537             renderer.setComponents(SoFCOffscreenRenderer::RGB_TRANSPARENCY );
00538             break;
00539         default:
00540             break;
00541     }
00542 
00543     SoSeparator* root = new SoSeparator;
00544     root->ref();
00545 
00546     SoCamera* camera = getCamera();
00547     if (useBackground) {
00548         root->addChild(backgroundroot);
00549         root->addChild(cb);
00550     }
00551     root->addChild(getHeadlight());
00552     root->addChild(camera);
00553     SoCallback* gl = new SoCallback;
00554     gl->setCallback(setGLWidget,this->getGLWidget());
00555     root->addChild(gl);
00556     root->addChild(pcViewProviderRoot);
00557     if (useBackground)
00558         root->addChild(cb);
00559     root->addChild(foregroundroot);
00560 
00561     try {
00562         // render the scene
00563         if (!renderer.render(root))
00564             throw Base::Exception("Offscreen rendering failed");
00565         // set matrix for miba
00566         renderer._Matrix = camera->getViewVolume().getMatrix();
00567         //bool ok = renderer.writeToImageFile(filename, filetypeextension);
00568         renderer.writeToImageFile(filename, comment);
00569         root->unref();
00570     }
00571     catch (...) {
00572         root->unref();
00573         throw; // re-throw exception
00574     }
00575 }
00576 
00577 void View3DInventorViewer::savePicture(int w, int h, int eBackgroundType, QImage& img) const
00578 {
00579     // if no valid color use the current background
00580     bool useBackground = false;
00581     SbViewportRegion vp(getViewportRegion());
00582     if (w>0 && h>0)
00583         vp.setWindowSize( (short)w, (short)h );
00584 
00585     //NOTE: To support pixels per inch we must use SbViewportRegion::setPixelsPerInch( ppi );
00586     //The default value is 72.0.
00587     //If we need to support grayscale images with must either use SoOffscreenRenderer::LUMINANCE or 
00588     //SoOffscreenRenderer::LUMINANCE_TRANSPARENCY. 
00589     SoFCOffscreenRenderer& renderer = SoFCOffscreenRenderer::instance();
00590     renderer.setViewportRegion(vp);
00591     SoCallback* cb = 0;
00592 
00593     // if we use transparency then we must not set a background color
00594     switch(eBackgroundType){
00595         case Current:
00596             useBackground = true;
00597             cb = new SoCallback;
00598             cb->setCallback(clearBuffer);
00599             break;
00600         case White:
00601             renderer.setBackgroundColor( SbColor(1.0, 1.0, 1.0) );
00602             break;
00603         case Black:
00604             renderer.setBackgroundColor( SbColor(0.0, 0.0, 0.0) );
00605             break;
00606         case Transparent:
00607             renderer.setComponents(SoFCOffscreenRenderer::RGB_TRANSPARENCY );
00608             break;
00609         default:
00610             break;
00611     }
00612 
00613     SoSeparator* root = new SoSeparator;
00614     root->ref();
00615 
00616     SoCamera* camera = getCamera();
00617     if (useBackground) {
00618         root->addChild(backgroundroot);
00619         root->addChild(cb);
00620     }
00621     root->addChild(getHeadlight());
00622     root->addChild(camera);
00623     SoCallback* gl = new SoCallback;
00624     gl->setCallback(setGLWidget, this->getGLWidget());
00625     root->addChild(gl);
00626     root->addChild(pcViewProviderRoot);
00627     if (useBackground)
00628         root->addChild(cb);
00629     root->addChild(foregroundroot);
00630 
00631     try {
00632         // render the scene
00633         if (!renderer.render(root))
00634             throw Base::Exception("Offscreen rendering failed");
00635         renderer.writeToImage(img);
00636         root->unref();
00637     }
00638     catch(...) {
00639         root->unref();
00640         throw; // re-throw exception
00641     }
00642 }
00643 
00644 void View3DInventorViewer::saveGraphic(int pagesize, int eBackgroundType, SoVectorizeAction* va) const
00645 {
00646     switch(eBackgroundType){
00647         case Current:
00648             va->setBackgroundColor(true, this->getBackgroundColor());
00649             break;
00650         case White:
00651             va->setBackgroundColor(true, SbColor(1.0, 1.0, 1.0));
00652             break;
00653         case Black:
00654             va->setBackgroundColor(true, SbColor(0.0, 0.0, 0.0));
00655             break;
00656         case Transparent:
00657             break; // not supported
00658         default:
00659             break;
00660     }
00661 
00662     float border = 10.0f;
00663     SbVec2s vpsize = this->getViewportRegion().getViewportSizePixels();
00664     float vpratio = ((float)vpsize[0]) / ((float)vpsize[1]); 
00665 
00666     if (vpratio > 1.0f) {
00667       va->setOrientation(SoVectorizeAction::LANDSCAPE);
00668       vpratio = 1.0f / vpratio;
00669     }
00670     else {
00671       va->setOrientation(SoVectorizeAction::PORTRAIT);
00672     }
00673 
00674     va->beginStandardPage(SoVectorizeAction::PageSize(pagesize), border);
00675 
00676     // try to fill as much "paper" as possible
00677     SbVec2f size = va->getPageSize();
00678 
00679     float pageratio = size[0] / size[1];
00680     float xsize, ysize;
00681 
00682     if (pageratio < vpratio) {
00683         xsize = size[0];
00684         ysize = xsize / vpratio;
00685     }
00686     else {
00687         ysize = size[1];
00688         xsize = ysize * vpratio;
00689     }
00690 
00691     float offx = border + (size[0]-xsize) * 0.5f;
00692     float offy = border + (size[1]-ysize) * 0.5f;
00693 
00694     va->beginViewport(SbVec2f(offx, offy), SbVec2f(xsize, ysize));
00695     va->calibrate(this->getViewportRegion());
00696     
00697     va->apply(this->getSceneManager()->getSceneGraph());
00698 
00699     va->endViewport();    
00700     va->endPage();
00701 }
00702 
00703 void View3DInventorViewer::startSelection(View3DInventorViewer::SelectionMode mode)
00704 {
00705     navigation->startSelection(NavigationStyle::SelectionMode(mode));
00706 }
00707 
00708 void View3DInventorViewer::stopSelection()
00709 {
00710     navigation->stopSelection();
00711 }
00712 
00713 bool View3DInventorViewer::isSelecting() const
00714 {
00715     return navigation->isSelecting();
00716 }
00717 
00718 const std::vector<SbVec2s>& View3DInventorViewer::getPolygon(SbBool* clip_inner) const
00719 {
00720     return navigation->getPolygon(clip_inner);
00721 }
00722 
00723 std::vector<SbVec2f> View3DInventorViewer::getGLPolygon(const std::vector<SbVec2s>& pnts) const
00724 {
00725     const SbViewportRegion& vp = this->getViewportRegion();
00726     const SbVec2s& sz = vp.getWindowSize();
00727     short w,h; sz.getValue(w,h);
00728     const SbVec2s& sp = vp.getViewportSizePixels();
00729     const SbVec2s& op = vp.getViewportOriginPixels();
00730     const SbVec2f& siz = vp.getViewportSize();
00731     float dX, dY; siz.getValue(dX, dY);
00732     float fRatio = vp.getViewportAspectRatio();
00733 
00734     std::vector<SbVec2f> poly;
00735     for (std::vector<SbVec2s>::const_iterator it = pnts.begin(); it != pnts.end(); ++it) {
00736         SbVec2s loc = *it - op;
00737         SbVec2f pos((float)loc[0]/(float)sp[0], (float)loc[1]/(float)sp[1]);
00738         float pX,pY; pos.getValue(pX,pY);
00739 
00740         // now calculate the real points respecting aspect ratio information
00741         //
00742         if (fRatio > 1.0f) {
00743             pX = (pX - 0.5f*dX) * fRatio + 0.5f*dX;
00744             pos.setValue(pX,pY);
00745         }
00746         else if (fRatio < 1.0f) {
00747             pY = (pY - 0.5f*dY) / fRatio + 0.5f*dY;
00748             pos.setValue(pX,pY);
00749         }
00750 
00751         poly.push_back(pos);
00752     }
00753 
00754     return poly;
00755 }
00756 
00757 std::vector<SbVec2f> View3DInventorViewer::getGLPolygon(SbBool* clip_inner) const
00758 {
00759     const std::vector<SbVec2s>& pnts = navigation->getPolygon(clip_inner);
00760     return getGLPolygon(pnts);
00761 }
00762 
00763 bool View3DInventorViewer::dumpToFile(const char* filename, bool binary) const
00764 {
00765     bool ret = false;
00766     Base::FileInfo fi(filename);
00767 
00768     // Write VRML V2.0
00769     if (fi.hasExtension("wrl") || fi.hasExtension("vrml") || fi.hasExtension("wrz")) {
00770         // If 'wrz' is set then force compression
00771         if (fi.hasExtension("wrz"))
00772             binary = true;
00773 
00774         SoToVRML2Action tovrml2;
00775         tovrml2.apply(pcViewProviderRoot);
00776         SoVRMLGroup *vrmlRoot = tovrml2.getVRML2SceneGraph();
00777         vrmlRoot->ref();
00778         std::string buffer = SoFCDB::writeNodesToString(vrmlRoot);
00779         vrmlRoot->unref(); // release the memory as soon as possible
00780 
00781         if (binary) {
00782             // We want to write compressed VRML but Coin 2.4.3 doesn't do it even though
00783             // SoOutput::getAvailableCompressionMethods() delivers a string list that
00784             // contains 'GZIP'. setCompression() was called directly after opening the file, 
00785             // returned TRUE and no error message appeared but anyway it didn't work.
00786             // Strange is that reading GZIPped VRML files works.
00787             // So, we do the compression on our own.
00788             Base::ofstream str(fi, std::ios::out | std::ios::binary);
00789             zipios::GZIPOutputStream gzip(str);
00790             if (gzip) {
00791                 gzip << buffer;
00792                 gzip.close();
00793                 ret = true;
00794             }
00795         }
00796         else {
00797             Base::ofstream str(fi, std::ios::out);
00798             if (str) {
00799                 str << buffer;
00800                 str.close();
00801                 ret = true;
00802             }
00803         }
00804     }
00805     else if (fi.hasExtension("idtf") || fi.hasExtension("svg") ) {
00806         int ps=4, t=2;
00807         std::auto_ptr<SoVectorizeAction> vo;
00808 
00809         if (fi.hasExtension("svg")) {
00810             vo = std::auto_ptr<SoVectorizeAction>(new SoFCVectorizeSVGAction());
00811         }
00812         else if (fi.hasExtension("idtf")) {
00813             vo = std::auto_ptr<SoVectorizeAction>(new SoFCVectorizeU3DAction());
00814         }
00815         else {
00816             throw Base::Exception("Not supported vector graphic");
00817         }
00818 
00819         SoVectorOutput * out = vo->getOutput();
00820         if (!out || !out->openFile(filename)) {
00821             std::ostringstream a_out;
00822             a_out << "Cannot open file '" << filename << "'";
00823             throw Base::Exception(a_out.str());
00824         }
00825 
00826         saveGraphic(ps,t,vo.get());
00827         out->closeFile();
00828     }
00829     else {
00830         // Write Inventor in ASCII
00831         std::string buffer = SoFCDB::writeNodesToString(pcViewProviderRoot);
00832         Base::ofstream str(Base::FileInfo(filename), std::ios::out);
00833         if (str) {
00834             str << buffer;
00835             str.close();
00836             ret = true;
00837         }
00838     }
00839 
00840     return ret;
00841 }
00842 
00846 void View3DInventorViewer::interactionStartCB(void * data, SoQtViewer * viewer)
00847 {
00848     SoGLRenderAction * glra = viewer->getGLRenderAction();
00849     SoFCInteractiveElement::set(glra->getState(), viewer->getSceneGraph(), true);
00850 }
00851 
00855 void View3DInventorViewer::interactionFinishCB(void * data, SoQtViewer * viewer)
00856 {
00857     SoGLRenderAction * glra = viewer->getGLRenderAction();
00858     SoFCInteractiveElement::set(glra->getState(), viewer->getSceneGraph(), false);
00859     viewer->render();
00860 }
00861 
00865 void View3DInventorViewer::interactionLoggerCB(void * ud, SoAction* action)
00866 {
00867     Base::Console().Log("%s\n", action->getTypeId().getName().getString());
00868 }
00869 
00870 // Documented in superclass. Overrides this method to be able to draw
00871 // the axis cross, if selected, and to keep a continuous animation
00872 // upon spin.
00873 void View3DInventorViewer::actualRedraw(void)
00874 {
00875     // Must set up the OpenGL viewport manually, as upon resize
00876     // operations, Coin won't set it up until the SoGLRenderAction is
00877     // applied again. And since we need to do glClear() before applying
00878     // the action..
00879     const SbViewportRegion vp = this->getViewportRegion();
00880     SbVec2s origin = vp.getViewportOriginPixels();
00881     SbVec2s size = vp.getViewportSizePixels();
00882     glViewport(origin[0], origin[1], size[0], size[1]);
00883 
00884     const SbColor col = this->getBackgroundColor();
00885     glClearColor(col[0], col[1], col[2], 0.0f);
00886     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00887 
00888     // using 90% of the z-buffer for the background and the main node
00889     glDepthRange(0.1,1.0);
00890 
00891     // Render our scenegraph with the image.
00892     SoGLRenderAction * glra = this->getGLRenderAction();
00893     SoGLWidgetElement::set(glra->getState(), qobject_cast<QGLWidget*>(this->getGLWidget()));
00894     SoGLRenderActionElement::set(glra->getState(), glra);
00895     glra->apply(this->backgroundroot);
00896 
00897     navigation->updateAnimation();
00898 
00899     try {
00900         // Render normal scenegraph.
00901         inherited::actualRedraw();
00902     } catch (const Base::MemoryException&) {
00903         // FIXME: If this exception appears then the background and camera position get broken somehow. (Werner 2006-02-01) 
00904         for ( std::set<ViewProvider*>::iterator it = _ViewProviderSet.begin(); it != _ViewProviderSet.end(); ++it )
00905             (*it)->hide();
00906         inherited::actualRedraw();
00907         QMessageBox::warning(getParentWidget(), QObject::tr("Out of memory"),
00908             QObject::tr("Not enough memory available to display the data."));
00909     }
00910 
00911     // using 10% of the z-buffer for the foreground node
00912     glDepthRange(0.0,0.1);
00913 
00914     // Render overlay front scenegraph.
00915     glra->apply(this->foregroundroot);
00916 
00917     if (this->axiscrossEnabled) { this->drawAxisCross(); }
00918    
00919     // using the main portion of z-buffer again (for frontbuffer highlighting)
00920     glDepthRange(0.1,1.0);
00921 
00922     // draw lines for the flags
00923     if (_flaglayout) {
00924         // it can happen that the GL widget gets replaced internally by SoQt which
00925         // causes to destroy the FlagLayout instance
00926         int ct = _flaglayout->count();
00927         SbViewVolume vv = getCamera()->getViewVolume(getGLAspectRatio());
00928         for (int i=0; i<ct;i++) {
00929             Flag* flag = qobject_cast<Flag*>(_flaglayout->itemAt(i)->widget());
00930             if (flag) {
00931                 SbVec3f pt = flag->getOrigin();
00932                 vv.projectToScreen(pt, pt);
00933                 int tox = (int)(pt[0] * size[0]);
00934                 int toy = (int)((1.0f-pt[1]) * size[1]);
00935                 flag->drawLine(tox, toy);
00936             }
00937         }
00938     }
00939 
00940     // Immediately reschedule to get continous spin animation.
00941     if (this->isAnimating()) { this->scheduleRedraw(); }
00942 
00943     printDimension();
00944     navigation->redraw();
00945 }
00946 
00947 void View3DInventorViewer::setSeekMode(SbBool on)
00948 {
00949     // Overrides this method to make sure any animations are stopped
00950     // before we go into seek mode.
00951 
00952     // Note: this method is almost identical to the setSeekMode() in the
00953     // SoQtFlyViewer and SoQtPlaneViewer, so migrate any changes.
00954 
00955     if (this->isAnimating()) { this->stopAnimating(); }
00956     inherited::setSeekMode(on);
00957     navigation->setViewingMode(on ? NavigationStyle::SEEK_WAIT_MODE :
00958                          (this->isViewing() ?
00959                          NavigationStyle::IDLE : NavigationStyle::INTERACT));
00960 }
00961 
00962 void View3DInventorViewer::printDimension()
00963 {
00964     SoCamera* cam = getCamera();
00965     if (!cam) return; // no camera there
00966     SoType t = getCamera()->getTypeId();
00967     if (t.isDerivedFrom(SoOrthographicCamera::getClassTypeId())) {
00968         const SbViewportRegion& vp = getViewportRegion();
00969         const SbVec2s& size = vp.getWindowSize();
00970         short dimX, dimY; size.getValue(dimX, dimY);
00971 
00972         float fHeight = static_cast<SoOrthographicCamera*>(getCamera())->height.getValue();
00973         float fWidth = fHeight;
00974         if (dimX > dimY)
00975             fWidth *= ((float)dimX)/((float)dimY);
00976         else if ( dimX < dimY )
00977             fHeight *= ((float)dimY)/((float)dimX);
00978 
00979         float fLog = float(log10(fWidth)), fFac;
00980         int   nExp = int(fLog);
00981         QString unit;
00982   
00983         if (nExp >= 6) {
00984             fFac = 1.0e+6f;
00985             unit = QLatin1String("km");
00986         }
00987         else if (nExp >= 3) {
00988             fFac = 1.0e+3f;
00989             unit = QLatin1String("m");
00990         }
00991         else if ((nExp >= 0) && (fLog > 0.0f)) {
00992             fFac = 1.0e+0f;
00993             unit = QLatin1String("mm");
00994         }
00995         else if (nExp >= -3) {
00996             fFac = 1.0e-3f;
00997             unit = QLatin1String("um");
00998         }
00999         else {
01000             fFac = 1.0e-6f;
01001             unit = QLatin1String("nm");
01002         }
01003 
01004         QString dim = QString::fromAscii("%1 x %2 %3")
01005                              .arg(fWidth / fFac,0,'f',2)
01006                              .arg(fHeight / fFac,0,'f',2)
01007                              .arg(unit);
01008         getMainWindow()->setPaneText(2, dim);
01009     }
01010     else
01011         getMainWindow()->setPaneText(2, QLatin1String(""));
01012 }
01013 
01014 void View3DInventorViewer::selectAll()
01015 {
01016     std::vector<App::DocumentObject*> objs;
01017     for (std::set<ViewProvider*>::iterator it = _ViewProviderSet.begin(); it != _ViewProviderSet.end(); ++it) {
01018          if ((*it)->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
01019              ViewProviderDocumentObject* vp = static_cast<ViewProviderDocumentObject*>(*it);
01020              App::DocumentObject* obj = vp->getObject();
01021              if (obj) objs.push_back(obj);
01022          }
01023     }
01024 
01025     if (!objs.empty())
01026         Gui::Selection().setSelection(objs.front()->getDocument()->getName(), objs);
01027 }
01028 
01034 void View3DInventorViewer::processEvent(QEvent * event)
01035 {
01036     if (event->type() == QEvent::KeyPress) {
01037         QKeyEvent* ke = static_cast<QKeyEvent*>(event);
01038         if (ke->matches(QKeySequence::SelectAll)) {
01039             selectAll();
01040             return;
01041         }
01042     }
01043     if (!Base::Sequencer().isRunning() ||
01044         !Base::Sequencer().isBlocking())
01045         inherited::processEvent(event);
01046 
01047     if (event->type() == Spaceball::ButtonEvent::ButtonEventType){
01048         Spaceball::ButtonEvent *buttonEvent = static_cast<Spaceball::ButtonEvent *>(event);
01049         if (!buttonEvent){
01050             Base::Console().Log("invalid spaceball button event\n");
01051             return;
01052         }
01053     }
01054 
01055     if (event->type() == Spaceball::MotionEvent::MotionEventType) {
01056         Spaceball::MotionEvent *motionEvent = static_cast<Spaceball::MotionEvent *>(event);
01057         if (!motionEvent){
01058             Base::Console().Log("invalid spaceball motion event\n");
01059             return;
01060         }
01061 
01062         static float translationConstant(-.001f);
01063         float xTrans, yTrans, zTrans;
01064         xTrans = static_cast<float>(motionEvent->translationX());
01065         yTrans = static_cast<float>(motionEvent->translationY());
01066         zTrans = static_cast<float>(motionEvent->translationZ());
01067         SbVec3f translationVector(xTrans, yTrans, zTrans * -1.0);
01068         translationVector *= translationConstant;
01069 
01070         static float rotationConstant(.0001f);
01071         SbRotation xRot, yRot, zRot;
01072         xRot.setValue(SbVec3f(-1.0, 0.0, 0.0), static_cast<float>(motionEvent->rotationX()) * rotationConstant);
01073         yRot.setValue(SbVec3f(0.0, -1.0, 0.0), static_cast<float>(motionEvent->rotationY()) * rotationConstant);
01074         zRot.setValue(SbVec3f(0.0, 0.0, 1.0), static_cast<float>(motionEvent->rotationZ()) * rotationConstant);
01075 
01076         SoMotion3Event motion3Event;
01077         motion3Event.setTranslation(translationVector);
01078         motion3Event.setRotation(xRot * yRot * zRot);
01079 
01080         this->processSoEvent(&motion3Event);
01081     }
01082 }
01083 
01084 SbBool View3DInventorViewer::processSoEvent(const SoEvent * const ev)
01085 {
01086     if (isRedirectedToSceneGraph()) {
01087         SbBool processed = SoQtRenderArea::processSoEvent(ev);
01088         if (!processed)
01089             processed = navigation->processEvent(ev);
01090         return processed;
01091     }
01092     if (ev->getTypeId().isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
01093         // filter out 'Q' and 'ESC' keys
01094         const SoKeyboardEvent * const ke = static_cast<const SoKeyboardEvent *>(ev);
01095         switch (ke->getKey()) {
01096         case SoKeyboardEvent::ESCAPE:
01097         case SoKeyboardEvent::Q: // ignore 'Q' keys (to prevent app from being closed)
01098             return SoQtRenderArea::processSoEvent(ev);
01099         default:
01100             break;
01101         }
01102     }
01103 
01104     return navigation->processEvent(ev);
01105 }
01106 
01107 SbBool View3DInventorViewer::processSoEventBase(const SoEvent * const ev)
01108 {
01109     return inherited::processSoEvent(ev);
01110 }
01111 
01112 SbVec3f View3DInventorViewer::getViewDirection() const
01113 {
01114     SoCamera* cam = this->getCamera();
01115     if (!cam) return SbVec3f(0,0,-1); // this is the default
01116     SbRotation camrot = cam->orientation.getValue();
01117     SbVec3f lookat(0, 0, -1); // init to default view direction vector
01118     camrot.multVec(lookat, lookat);
01119     return lookat;
01120 }
01121 
01122 SbVec3f View3DInventorViewer::getUpDirection() const
01123 {
01124     SoCamera* cam = this->getCamera();
01125     if (!cam) return SbVec3f(0,1,0);
01126     SbRotation camrot = cam->orientation.getValue();
01127     SbVec3f upvec(0, 1, 0); // init to default up vector
01128     camrot.multVec(upvec, upvec);
01129     return upvec;
01130 }
01131 
01132 SbVec3f View3DInventorViewer::getPointOnScreen(const SbVec2s& pnt) const
01133 {
01134     const SbViewportRegion& vp = this->getViewportRegion();
01135 
01136     short x,y; pnt.getValue(x,y);
01137     SbVec2f siz = vp.getViewportSize();
01138     float dX, dY; siz.getValue(dX, dY);
01139 
01140     float fRatio = vp.getViewportAspectRatio();
01141     float pX = (float)x / float(vp.getViewportSizePixels()[0]);
01142     float pY = (float)y / float(vp.getViewportSizePixels()[1]);
01143 
01144     // now calculate the real points respecting aspect ratio information
01145     //
01146     if (fRatio > 1.0f) {
01147         pX = (pX - 0.5f*dX) * fRatio + 0.5f*dX;
01148     }
01149     else if (fRatio < 1.0f) {
01150         pY = (pY - 0.5f*dY) / fRatio + 0.5f*dY;
01151     }
01152 
01153     SoCamera* pCam = this->getCamera();
01154     if (!pCam) return SbVec3f(); // return invalid point
01155     SbViewVolume  vol = pCam->getViewVolume();
01156 
01157     float nearDist = pCam->nearDistance.getValue();
01158     float farDist = pCam->farDistance.getValue();
01159     float focalDist = pCam->focalDistance.getValue();
01160     if (focalDist < nearDist || focalDist > farDist)
01161         focalDist = 0.5f*(nearDist + farDist);
01162 
01163     SbLine line; SbVec3f pt;
01164     SbPlane focalPlane = vol.getPlane(focalDist);
01165     vol.projectPointToLine(SbVec2f(pX,pY), line);
01166     focalPlane.intersect(line, pt);
01167     
01168     return pt;
01169 }
01170 
01171 void View3DInventorViewer::getNearPlane(SbVec3f& rcPt, SbVec3f& rcNormal) const
01172 {
01173     SoCamera* pCam = getCamera();
01174     if (!pCam) return; // just do nothing
01175     SbViewVolume vol = pCam->getViewVolume();
01176 
01177     // get the normal of the front clipping plane
01178     SbPlane nearPlane = vol.getPlane(vol.nearDist);
01179     float d = nearPlane.getDistanceFromOrigin();
01180     rcNormal = nearPlane.getNormal();
01181     rcNormal.normalize();
01182     float nx, ny, nz; rcNormal.getValue(nx, ny, nz);
01183     rcPt.setValue(d*rcNormal[0], d*rcNormal[1], d*rcNormal[2]);
01184 }
01185 
01186 void View3DInventorViewer::getFarPlane(SbVec3f& rcPt, SbVec3f& rcNormal) const
01187 {
01188     SoCamera* pCam = getCamera();
01189     if (!pCam) return; // just do nothing
01190     SbViewVolume vol = pCam->getViewVolume();
01191 
01192     // get the normal of the back clipping plane
01193     SbPlane farPlane = vol.getPlane(vol.nearDist+vol.nearToFar);
01194     float d = farPlane.getDistanceFromOrigin();
01195     rcNormal = farPlane.getNormal();
01196     rcNormal.normalize();
01197     float nx, ny, nz; rcNormal.getValue(nx, ny, nz);
01198     rcPt.setValue(d*rcNormal[0], d*rcNormal[1], d*rcNormal[2]);
01199 }
01200 
01201 SbVec3f View3DInventorViewer::projectOnNearPlane(const SbVec2f& pt) const
01202 {
01203     SbVec3f pt1, pt2;
01204     SoCamera* cam = this->getCamera();
01205     if (!cam) return SbVec3f(); // return invalid point
01206     SbViewVolume vol = cam->getViewVolume();
01207     vol.projectPointToLine(pt, pt1, pt2);
01208     return pt1;
01209 }
01210 
01211 SbVec3f View3DInventorViewer::projectOnFarPlane(const SbVec2f& pt) const
01212 {
01213     SbVec3f pt1, pt2;
01214     SoCamera* cam = this->getCamera();
01215     if (!cam) return SbVec3f(); // return invalid point
01216     SbViewVolume vol = cam->getViewVolume();
01217     vol.projectPointToLine(pt, pt1, pt2);
01218     return pt2;
01219 }
01220 
01221 void View3DInventorViewer::toggleClippingPlane()
01222 {
01223     if (pcViewProviderRoot->getNumChildren() > 0 && 
01224         pcViewProviderRoot->getChild(0)->getTypeId() == 
01225         SoClipPlaneManip::getClassTypeId()) {
01226         pcViewProviderRoot->removeChild(0);
01227     }
01228     else {
01229         SoClipPlaneManip* clip = new SoClipPlaneManip;
01230         SoGetBoundingBoxAction action(this->getViewportRegion());
01231         action.apply(this->getSceneGraph());
01232         SbBox3f box = action.getBoundingBox();
01233 
01234         if (!box.isEmpty()) {
01235             // adjust to overall bounding box of the scene
01236             clip->setValue(box, SbVec3f(0.0f,0.0f,1.0f), 1.0f);
01237         }
01238 
01239         pcViewProviderRoot->insertChild(clip,0);
01240     }
01241 }
01242 
01243 bool View3DInventorViewer::hasClippingPlane() const
01244 {
01245     if (pcViewProviderRoot && pcViewProviderRoot->getNumChildren() > 0) {
01246         return (pcViewProviderRoot->getChild(0)->getTypeId()
01247             == SoClipPlaneManip::getClassTypeId());
01248     }
01249 
01250     return false;
01251 }
01252 
01258 bool View3DInventorViewer::pickPoint(const SbVec2s& pos,SbVec3f &point,SbVec3f &norm) const
01259 {
01260     // attempting raypick in the event_cb() callback method
01261     SoRayPickAction rp(getViewportRegion());
01262     rp.setPoint(pos);
01263     rp.apply(getSceneManager()->getSceneGraph());
01264     SoPickedPoint *Point = rp.getPickedPoint();
01265 
01266     if (Point) {
01267         point = Point->getObjectPoint();
01268         norm  = Point->getObjectNormal();
01269         return true;
01270     }
01271 
01272     return false;
01273 }
01274 
01281 SoPickedPoint* View3DInventorViewer::pickPoint(const SbVec2s& pos) const
01282 {
01283     SoRayPickAction rp(getViewportRegion());
01284     rp.setPoint(pos);
01285     rp.apply(getSceneManager()->getSceneGraph());
01286 
01287     // returns a copy of the point
01288     SoPickedPoint* pick = rp.getPickedPoint();
01289     //return (pick ? pick->copy() : 0); // needs the same instance of CRT under MS Windows
01290     return (pick ? new SoPickedPoint(*pick) : 0);
01291 }
01292 
01293 SbBool View3DInventorViewer::pubSeekToPoint(const SbVec2s& pos)
01294 {
01295     return this->seekToPoint(pos);
01296 }
01297 
01298 void View3DInventorViewer::pubSeekToPoint(const SbVec3f& pos)
01299 {
01300     this->seekToPoint(pos);
01301 }
01302 
01303 void View3DInventorViewer::setCameraOrientation(const SbRotation& rot)
01304 {
01305     navigation->setCameraOrientation(rot);
01306 }
01307 
01308 void View3DInventorViewer::setCameraType(SoType t)
01309 {
01310     inherited::setCameraType(t);
01311     if (t.isDerivedFrom(SoPerspectiveCamera::getClassTypeId())) {
01312         // When doing a viewAll() for an orthographic camera and switching
01313         // to perspective the scene looks completely srange because of the
01314         // heightAngle. Setting it to 45 deg also causes an issue with a too
01315         // close camera but we don't have this other ugly effect.
01316         SoCamera* cam = this->getCamera();
01317         if (cam == 0) return;
01318         static_cast<SoPerspectiveCamera*>(cam)->heightAngle = (float)(M_PI / 4.0);
01319     }
01320 }
01321 
01322 void View3DInventorViewer::moveCameraTo(const SbRotation& rot, const SbVec3f& pos, int steps, int ms)
01323 {
01324     SoCamera* cam = this->getCamera();
01325     if (cam == 0) return;
01326 
01327     SbVec3f campos = cam->position.getValue();
01328     SbRotation camrot = cam->orientation.getValue();
01329     //SbVec3f dir1, dir2;
01330     //camrot.multVec(SbVec3f(0, 0, -1), dir1);
01331     //rot.multVec(SbVec3f(0, 0, -1), dir2);
01332 
01333     QEventLoop loop;
01334     QTimer timer;
01335     timer.setSingleShot(true);
01336     QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
01337     for (int i=0; i<steps; i++) {
01338         float s = float(i)/float(steps);
01339         SbVec3f curpos = campos * (1.0f-s) + pos * s;
01340         SbRotation currot = SbRotation::slerp(camrot, rot, s);
01341         cam->orientation.setValue(currot);
01342         cam->position.setValue(curpos);
01343         timer.start(Base::clamp<int>(ms,0,5000));
01344         loop.exec(QEventLoop::ExcludeUserInputEvents);
01345     }
01346 
01347     cam->orientation.setValue(rot);
01348     cam->position.setValue(pos);
01349 }
01350 
01351 void View3DInventorViewer::boxZoom(const SbBox2s& box)
01352 {
01353     navigation->boxZoom(box);
01354 }
01355 
01356 void View3DInventorViewer::viewAll()
01357 {
01358     // in the scene graph we may have objects which we want to exlcude
01359     // when doing a fit all. Such objects must be part of the group
01360     // SoSkipBoundingGroup.
01361     SoSearchAction sa;
01362     sa.setType(SoSkipBoundingGroup::getClassTypeId());
01363     sa.setInterest(SoSearchAction::ALL);
01364     sa.apply(this->getSceneGraph());
01365     const SoPathList & pathlist = sa.getPaths();
01366     for (int i = 0; i < pathlist.getLength(); i++ ) {
01367         SoPath * path = pathlist[i];
01368         SoSkipBoundingGroup * group = static_cast<SoSkipBoundingGroup*>(path->getTail());
01369         group->mode = SoSkipBoundingGroup::EXCLUDE_BBOX;
01370     }
01371 
01372     // call the default implementation first to make sure everything is visible
01373     SoQtViewer::viewAll();
01374 
01375     for (int i = 0; i < pathlist.getLength(); i++ ) {
01376         SoPath * path = pathlist[i];
01377         SoSkipBoundingGroup * group = static_cast<SoSkipBoundingGroup*>(path->getTail());
01378         group->mode = SoSkipBoundingGroup::INCLUDE_BBOX;
01379     }
01380     //navigation->viewAll();
01381 }
01382 
01383 void View3DInventorViewer::viewAll(float factor)
01384 {
01385     SoCamera * cam = this->getCamera();
01386     if (!cam) return;
01387     if (factor <= 0.0f) return;
01388 
01389     if (factor != 1.0f) {
01390         SoSearchAction sa;
01391         sa.setType(SoSkipBoundingGroup::getClassTypeId());
01392         sa.setInterest(SoSearchAction::ALL);
01393         sa.apply(this->getSceneGraph());
01394         const SoPathList & pathlist = sa.getPaths();
01395         for (int i = 0; i < pathlist.getLength(); i++ ) {
01396             SoPath * path = pathlist[i];
01397             SoSkipBoundingGroup * group = static_cast<SoSkipBoundingGroup*>(path->getTail());
01398             group->mode = SoSkipBoundingGroup::EXCLUDE_BBOX;
01399         }
01400 
01401         SoGetBoundingBoxAction action(this->getViewportRegion());
01402         action.apply(this->getSceneGraph());
01403         SbBox3f box = action.getBoundingBox();
01404         float minx,miny,minz,maxx,maxy,maxz;
01405         box.getBounds(minx,miny,minz,maxx,maxy,maxz);
01406 
01407         for (int i = 0; i < pathlist.getLength(); i++ ) {
01408             SoPath * path = pathlist[i];
01409             SoSkipBoundingGroup * group = static_cast<SoSkipBoundingGroup*>(path->getTail());
01410             group->mode = SoSkipBoundingGroup::INCLUDE_BBOX;
01411         }
01412 
01413         SoCube * cube = new SoCube();
01414         cube->width  = factor*(maxx-minx);
01415         cube->height = factor*(maxy-miny);
01416         cube->depth  = factor*(maxz-minz);
01417 
01418         // fake a scenegraph with the desired bounding size
01419         SoSeparator* graph = new SoSeparator();
01420         graph->ref();
01421         SoTranslation * tr = new SoTranslation();
01422         tr->translation.setValue(box.getCenter());
01423 
01424         graph->addChild(tr);
01425         graph->addChild(cube);
01426         cam->viewAll(graph, this->getViewportRegion());
01427         graph->unref();
01428     }
01429     else {
01430         viewAll();
01431     }
01432 }
01433 
01434 void View3DInventorViewer::viewSelection()
01435 {
01436     // Search for all SoFCSelection nodes
01437     SoSearchAction searchAction;
01438     searchAction.setType(SoFCSelection::getClassTypeId());
01439     searchAction.setInterest(SoSearchAction::ALL);
01440     searchAction.apply(pcViewProviderRoot);
01441 
01442     SoPathList& paths = searchAction.getPaths();
01443     int countPaths = paths.getLength();
01444 
01445     SoGroup* root = new SoGroup();
01446     root->ref();
01447 
01448     for (int i=0; i<countPaths;i++) {
01449         SoPath* path = paths[i];
01450         SoNode* node = path->getTail();
01451         if (!node || node->getTypeId() != SoFCSelection::getClassTypeId())
01452             continue; // should not happen
01453         SoFCSelection* select = static_cast<SoFCSelection *>(node);
01454         // Check only document and object name but not sub-element name
01455         if (Selection().isSelected(select->documentName.getValue().getString(),
01456                                    select->objectName.getValue().getString())
01457                                    ) {
01458             root->addChild(select);
01459         }
01460     }
01461 
01462     SoCamera* cam = this->getCamera();
01463     if (cam) cam->viewAll(root, this->getViewportRegion());
01464     root->unref();
01465 }
01466 
01467 // Draw routines
01468 void View3DInventorViewer::drawRect(int x1, int y1, int x2, int y2)
01469 {
01470     // Make current context
01471     SbVec2s view = this->getGLSize();
01472     this->glLockNormal();
01473 
01474     glMatrixMode(GL_PROJECTION);
01475     glPushMatrix();
01476     glLoadIdentity();
01477     glOrtho(0, view[0], 0, view[1], -1, 1);
01478 
01479     // Store GL state
01480     glPushAttrib(GL_ALL_ATTRIB_BITS);
01481     GLfloat depthrange[2];
01482     glGetFloatv(GL_DEPTH_RANGE, depthrange);
01483     GLdouble projectionmatrix[16];
01484     glGetDoublev(GL_PROJECTION_MATRIX, projectionmatrix);
01485 
01486     glDepthFunc(GL_ALWAYS);
01487     glDepthMask(GL_TRUE);
01488     glDepthRange(0,0);
01489     glEnable(GL_DEPTH_TEST);
01490     glDisable(GL_LIGHTING);
01491     glEnable(GL_COLOR_MATERIAL);
01492     glDisable(GL_BLEND);
01493 
01494     glEnable(GL_COLOR_LOGIC_OP);
01495     glLogicOp(GL_XOR);
01496     glDrawBuffer(GL_FRONT);
01497     glLineWidth(3.0f);
01498     glEnable(GL_LINE_STIPPLE);
01499     glLineStipple(2, 0x3F3F);
01500     glColor4f(1.0, 1.0, 0.0, 0.0);
01501     glViewport(0, 0, view[0], view[1]);
01502 
01503     glBegin(GL_LINE_LOOP);
01504         glVertex3i(x1, view[1]-y1, 0);
01505         glVertex3i(x2, view[1]-y1, 0);
01506         glVertex3i(x2, view[1]-y2, 0);
01507         glVertex3i(x1, view[1]-y2, 0);
01508     glEnd();
01509 
01510     glFlush();
01511     glDisable(GL_LINE_STIPPLE);
01512     glDisable(GL_COLOR_LOGIC_OP);
01513 
01514     // Reset original state
01515     glDepthRange(depthrange[0], depthrange[1]);
01516     glMatrixMode(GL_PROJECTION);
01517     glLoadMatrixd(projectionmatrix);
01518 
01519     glPopAttrib();
01520     glPopMatrix();
01521     
01522     // Release the context
01523     this->glUnlockNormal();
01524 }
01525 
01526 void View3DInventorViewer::drawLine (int x1, int y1, int x2, int y2)
01527 {
01528     // Make current context
01529     SbVec2s view = this->getGLSize();
01530     this->glLockNormal();
01531 
01532     glMatrixMode(GL_PROJECTION);
01533     glPushMatrix();
01534     glLoadIdentity();
01535     glOrtho(0, view[0], 0, view[1], -1, 1);
01536 
01537     // Store GL state
01538     glPushAttrib(GL_ALL_ATTRIB_BITS);
01539     GLfloat depthrange[2];
01540     glGetFloatv(GL_DEPTH_RANGE, depthrange);
01541     GLdouble projectionmatrix[16];
01542     glGetDoublev(GL_PROJECTION_MATRIX, projectionmatrix);
01543 
01544     glDepthFunc(GL_ALWAYS);
01545     glDepthMask(GL_TRUE);
01546     glDepthRange(0,0);
01547     glEnable(GL_DEPTH_TEST);
01548     glDisable(GL_LIGHTING);
01549     glEnable(GL_COLOR_MATERIAL);
01550     glDisable(GL_BLEND);
01551 
01552     glLineWidth(1.0f);
01553     glColor4f(1.0, 1.0, 1.0, 0.0);
01554     glViewport(0, 0, view[0], view[1]);
01555 
01556     glEnable(GL_COLOR_LOGIC_OP);
01557     glLogicOp(GL_XOR);
01558     glDrawBuffer(GL_FRONT);
01559 
01560     glBegin(GL_LINES);
01561         glVertex3i(x1, view[1]-y1, 0);
01562         glVertex3i(x2, view[1]-y2, 0);
01563     glEnd();
01564 
01565     glFlush();
01566     glLogicOp(GL_COPY);
01567     glDisable(GL_COLOR_LOGIC_OP);
01568 
01569     // Reset original state
01570     glDepthRange(depthrange[0], depthrange[1]);
01571     glMatrixMode(GL_PROJECTION);
01572     glLoadMatrixd(projectionmatrix);
01573 
01574     glPopAttrib();
01575     glPopMatrix();
01576     
01577     // Release the context
01578     this->glUnlockNormal();
01579 }
01580 
01588 void
01589 View3DInventorViewer::setAnimationEnabled(const SbBool enable)
01590 {
01591     navigation->setAnimationEnabled(enable);
01592 }
01593 
01599 SbBool
01600 View3DInventorViewer::isAnimationEnabled(void) const
01601 {
01602     return navigation->isAnimationEnabled();
01603 }
01604 
01609 SbBool View3DInventorViewer::isAnimating(void) const
01610 {
01611     return navigation->isAnimating();
01612 }
01613 
01618 void View3DInventorViewer::startAnimating(const SbVec3f& axis, float velocity)
01619 {
01620     navigation->startAnimating(axis, velocity);
01621 }
01622 
01623 void View3DInventorViewer::stopAnimating(void)
01624 {
01625     navigation->stopAnimating();
01626 }
01627 
01632 void
01633 View3DInventorViewer::setFeedbackVisibility(const SbBool enable)
01634 {
01635     if (enable == this->axiscrossEnabled) {
01636         return;
01637     }
01638     this->axiscrossEnabled = enable;
01639 
01640     if (this->isViewing()) { this->scheduleRedraw(); }
01641 }
01642 
01647 SbBool
01648 View3DInventorViewer::isFeedbackVisible(void) const
01649 {
01650     return this->axiscrossEnabled;
01651 }
01652 
01658 void
01659 View3DInventorViewer::setFeedbackSize(const int size)
01660 {
01661     if (size < 1) {
01662         return;
01663     }
01664 
01665     this->axiscrossSize = size;
01666 
01667     if (this->isFeedbackVisible() && this->isViewing()) {
01668         this->scheduleRedraw();
01669     }
01670 }
01671 
01676 int
01677 View3DInventorViewer::getFeedbackSize(void) const
01678 {
01679     return this->axiscrossSize;
01680 }
01681 
01686 void View3DInventorViewer::setCursorEnabled(SbBool enable)
01687 {
01688     inherited::setCursorEnabled(enable);
01689     this->setCursorRepresentation(navigation->getViewingMode());
01690 }
01691 
01692 void View3DInventorViewer::afterRealizeHook(void)
01693 {
01694     inherited::afterRealizeHook();
01695     this->setCursorRepresentation(navigation->getViewingMode());
01696 }
01697 
01698 // Documented in superclass. This method overridden from parent class
01699 // to make sure the mouse pointer cursor is updated.
01700 void View3DInventorViewer::setViewing(SbBool enable)
01701 {
01702     if (this->isViewing() == enable) {
01703         return;
01704     }
01705 
01706     navigation->setViewingMode(enable ?
01707         NavigationStyle::IDLE : NavigationStyle::INTERACT);
01708     inherited::setViewing(enable);
01709 }
01710 
01711 //****************************************************************************
01712 
01713 // Bitmap representations of an "X", a "Y" and a "Z" for the axis cross.
01714 static GLubyte xbmp[] = { 0x11,0x11,0x0a,0x04,0x0a,0x11,0x11 };
01715 static GLubyte ybmp[] = { 0x04,0x04,0x04,0x04,0x0a,0x11,0x11 };
01716 static GLubyte zbmp[] = { 0x1f,0x10,0x08,0x04,0x02,0x01,0x1f };
01717 
01718 void View3DInventorViewer::drawAxisCross(void)
01719 {
01720   // FIXME: convert this to a superimposition scenegraph instead of
01721   // OpenGL calls. 20020603 mortene.
01722 
01723   // Store GL state.
01724   glPushAttrib(GL_ALL_ATTRIB_BITS);
01725   GLfloat depthrange[2];
01726   glGetFloatv(GL_DEPTH_RANGE, depthrange);
01727   GLdouble projectionmatrix[16];
01728   glGetDoublev(GL_PROJECTION_MATRIX, projectionmatrix);
01729 
01730   glDepthFunc(GL_ALWAYS);
01731   glDepthMask(GL_TRUE);
01732   glDepthRange(0, 0);
01733   glEnable(GL_DEPTH_TEST);
01734   glDisable(GL_LIGHTING);
01735   glEnable(GL_COLOR_MATERIAL);
01736   glDisable(GL_BLEND); // Kills transparency.
01737 
01738   // Set the viewport in the OpenGL canvas. Dimensions are calculated
01739   // as a percentage of the total canvas size.
01740   SbVec2s view = this->getGLSize();
01741   const int pixelarea =
01742     int(float(this->axiscrossSize)/100.0f * SoQtMin(view[0], view[1]));
01743 #if 0 // middle of canvas
01744   SbVec2s origin(view[0]/2 - pixelarea/2, view[1]/2 - pixelarea/2);
01745 #endif // middle of canvas
01746 #if 1 // lower right of canvas
01747   SbVec2s origin(view[0] - pixelarea, 0);
01748 #endif // lower right of canvas
01749   glViewport(origin[0], origin[1], pixelarea, pixelarea);
01750 
01751 
01752   // Set up the projection matrix.
01753   glMatrixMode(GL_PROJECTION);
01754   glLoadIdentity();
01755 
01756   const float NEARVAL = 0.1f;
01757   const float FARVAL = 10.0f;
01758   const float dim = NEARVAL * float(tan(M_PI / 8.0)); // FOV is 45° (45/360 = 1/8)
01759   glFrustum(-dim, dim, -dim, dim, NEARVAL, FARVAL);
01760 
01761 
01762   // Set up the model matrix.
01763   glMatrixMode(GL_MODELVIEW);
01764   glPushMatrix();
01765   SbMatrix mx;
01766   SoCamera * cam = this->getCamera();
01767 
01768   // If there is no camera (like for an empty scene, for instance),
01769   // just use an identity rotation.
01770   if (cam) { mx = cam->orientation.getValue(); }
01771   else { mx = SbMatrix::identity(); }
01772 
01773   mx = mx.inverse();
01774   mx[3][2] = -3.5; // Translate away from the projection point (along z axis).
01775   glLoadMatrixf((float *)mx);
01776 
01777 
01778   // Find unit vector end points.
01779   SbMatrix px;
01780   glGetFloatv(GL_PROJECTION_MATRIX, (float *)px);
01781   SbMatrix comb = mx.multRight(px);
01782 
01783   SbVec3f xpos;
01784   comb.multVecMatrix(SbVec3f(1,0,0), xpos);
01785   xpos[0] = (1 + xpos[0]) * view[0]/2;
01786   xpos[1] = (1 + xpos[1]) * view[1]/2;
01787   SbVec3f ypos;
01788   comb.multVecMatrix(SbVec3f(0,1,0), ypos);
01789   ypos[0] = (1 + ypos[0]) * view[0]/2;
01790   ypos[1] = (1 + ypos[1]) * view[1]/2;
01791   SbVec3f zpos;
01792   comb.multVecMatrix(SbVec3f(0,0,1), zpos);
01793   zpos[0] = (1 + zpos[0]) * view[0]/2;
01794   zpos[1] = (1 + zpos[1]) * view[1]/2;
01795 
01796 
01797   // Render the cross.
01798   {
01799     glLineWidth(2.0);
01800 
01801     enum { XAXIS, YAXIS, ZAXIS };
01802     int idx[3] = { XAXIS, YAXIS, ZAXIS };
01803     float val[3] = { xpos[2], ypos[2], zpos[2] };
01804 
01805     // Bubble sort.. :-}
01806     if (val[0] < val[1]) { SoQtSwap(val[0], val[1]); SoQtSwap(idx[0], idx[1]); }
01807     if (val[1] < val[2]) { SoQtSwap(val[1], val[2]); SoQtSwap(idx[1], idx[2]); }
01808     if (val[0] < val[1]) { SoQtSwap(val[0], val[1]); SoQtSwap(idx[0], idx[1]); }
01809     assert((val[0] >= val[1]) && (val[1] >= val[2])); // Just checking..
01810 
01811     for (int i=0; i < 3; i++) {
01812       glPushMatrix();
01813       if (idx[i] == XAXIS) {                       // X axis.
01814         if (isStereoViewing())
01815           glColor3f(0.500f, 0.5f, 0.5f);
01816         else
01817           glColor3f(0.500f, 0.125f, 0.125f);
01818       } else if (idx[i] == YAXIS) {                // Y axis.
01819         glRotatef(90, 0, 0, 1);
01820         if (isStereoViewing())
01821           glColor3f(0.400f, 0.4f, 0.4f);
01822         else
01823           glColor3f(0.125f, 0.500f, 0.125f);
01824       } else {                                     // Z axis.
01825         glRotatef(-90, 0, 1, 0);
01826         if (isStereoViewing())
01827           glColor3f(0.300f, 0.3f, 0.3f);
01828         else
01829           glColor3f(0.125f, 0.125f, 0.500f);
01830       }
01831       this->drawArrow(); 
01832       glPopMatrix();
01833     }
01834   }
01835 
01836   // Render axis notation letters ("X", "Y", "Z").
01837   glMatrixMode(GL_PROJECTION);
01838   glLoadIdentity();
01839   glOrtho(0, view[0], 0, view[1], -1, 1);
01840 
01841   glMatrixMode(GL_MODELVIEW);
01842   glLoadIdentity();
01843 
01844   GLint unpack;
01845   glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack);
01846   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
01847 
01848   if(isStereoViewing())
01849     glColor3fv(SbVec3f(1.0f, 1.0f, 1.0f).getValue());
01850   else
01851     glColor3fv(SbVec3f(0.0f, 0.0f, 0.0f).getValue());
01852 
01853   glRasterPos2d(xpos[0], xpos[1]);
01854   glBitmap(8, 7, 0, 0, 0, 0, xbmp);
01855   glRasterPos2d(ypos[0], ypos[1]);
01856   glBitmap(8, 7, 0, 0, 0, 0, ybmp);
01857   glRasterPos2d(zpos[0], zpos[1]);
01858   glBitmap(8, 7, 0, 0, 0, 0, zbmp);
01859 
01860   glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
01861   glPopMatrix();
01862 
01863   // Reset original state.
01864 
01865   // FIXME: are these 3 lines really necessary, as we push
01866   // GL_ALL_ATTRIB_BITS at the start? 20000604 mortene.
01867   glDepthRange(depthrange[0], depthrange[1]);
01868   glMatrixMode(GL_PROJECTION);
01869   glLoadMatrixd(projectionmatrix);
01870 
01871   glPopAttrib();
01872 }
01873 
01874 // Draw an arrow for the axis representation directly through OpenGL.
01875 void View3DInventorViewer::drawArrow(void)
01876 {
01877     glBegin(GL_LINES);
01878     glVertex3f(0.0f, 0.0f, 0.0f);
01879     glVertex3f(1.0f, 0.0f, 0.0f);
01880     glEnd();
01881     glDisable(GL_CULL_FACE);
01882     glBegin(GL_TRIANGLES);
01883     glVertex3f(1.0f, 0.0f, 0.0f);
01884     glVertex3f(1.0f - 1.0f / 3.0f, +0.5f / 4.0f, 0.0f);
01885     glVertex3f(1.0f - 1.0f / 3.0f, -0.5f / 4.0f, 0.0f);
01886     glVertex3f(1.0f, 0.0f, 0.0f);
01887     glVertex3f(1.0f - 1.0f / 3.0f, 0.0f, +0.5f / 4.0f);
01888     glVertex3f(1.0f - 1.0f / 3.0f, 0.0f, -0.5f / 4.0f);
01889     glEnd();
01890     glBegin(GL_QUADS);
01891     glVertex3f(1.0f - 1.0f / 3.0f, +0.5f / 4.0f, 0.0f);
01892     glVertex3f(1.0f - 1.0f / 3.0f, 0.0f, +0.5f / 4.0f);
01893     glVertex3f(1.0f - 1.0f / 3.0f, -0.5f / 4.0f, 0.0f);
01894     glVertex3f(1.0f - 1.0f / 3.0f, 0.0f, -0.5f / 4.0f);
01895     glEnd();
01896 }
01897 
01898 // ************************************************************************
01899 
01900 #define HAND_WITH 24
01901 #define HAND_HEIGHT 24
01902 #define HAND_HOT_X 9
01903 #define HAND_HOT_Y 0
01904 
01905 static unsigned char hand_bitmap[] = {
01906     0x00,0x03,0x00,0x80,0x04,0x00,0x80,0x04,0x00,0x80,0x04,0x00,0x80,0x04,0x00,
01907     0x80,0x1c,0x00,0x80,0xe4,0x00,0x80,0x24,0x01,0x80,0x24,0x07,0x8e,0x24,0x09,
01908     0x92,0x24,0x09,0xa4,0x00,0x09,0xc4,0x00,0x08,0x08,0x00,0x08,0x08,0x00,0x08,
01909     0x10,0x00,0x08,0x10,0x00,0x04,0x20,0x00,0x04,0x20,0x00,0x04,0x40,0x00,0x02,
01910     0x80,0x00,0x02,0x00,0x01,0x01,0x00,0xff,0x01,0x00,0x00,0x00,0x00,0xab,0xab,
01911     0xab,0xab,0xab,0xab,0xab,0xab,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,
01912     0x00,0x1b,0x00,0xee,0x04,0xee };
01913 
01914 static unsigned char hand_mask_bitmap[] = {
01915     0x00,0x03,0x00,0x80,0x07,0x00,0x80,0x07,0x00,0x80,0x07,0x00,0x80,0x07,0x00,
01916     0x80,0x1f,0x00,0x80,0xff,0x00,0x80,0xff,0x01,0x80,0xff,0x07,0x8e,0xff,0x0f,
01917     0x9e,0xff,0x0f,0xbc,0xff,0x0f,0xfc,0xff,0x0f,0xf8,0xff,0x0f,0xf8,0xff,0x0f,
01918     0xf0,0xff,0x0f,0xf0,0xff,0x07,0xe0,0xff,0x07,0xe0,0xff,0x07,0xc0,0xff,0x03,
01919     0x80,0xff,0x03,0x00,0xff,0x01,0x00,0xff,0x01,0x00,0x00,0x00,0x00,0xab,0xab,
01920     0xab,0xab,0xab,0xab,0xab,0xab,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,
01921     0x00,0x1b,0x00,0xd5,0x07,0x1c };
01922 
01923 #define CROSS_WIDTH 16
01924 #define CROSS_HEIGHT 16
01925 #define CROSS_HOT_X 7
01926 #define CROSS_HOT_Y 7
01927 
01928 static unsigned char cross_bitmap[] = {
01929   0xc0, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02,
01930   0x40, 0x02, 0x40, 0x02, 0x7f, 0xfe, 0x01, 0x80,
01931   0x01, 0x80, 0x7f, 0xfe, 0x40, 0x02, 0x40, 0x02,
01932   0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0xc0, 0x03
01933 };
01934 
01935 static unsigned char cross_mask_bitmap[] = {
01936  0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xff,0xff,0xff,
01937  0xff,0xff,0xff,0xff,0xff,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,
01938  0xc0,0x03
01939 };
01940 
01941 // Set cursor graphics according to mode.
01942 void View3DInventorViewer::setCursorRepresentation(int modearg)
01943 {
01944     // There is a synchronization problem between Qt and SoQt which
01945     // happens when popping up a context-menu. In this case the
01946     // Qt::WA_UnderMouse attribute is resetted and never set again
01947     // even if the mouse is still in the canvas. Thus, the cursor
01948     // won't be changed as long as the user doesn't leave and enter
01949     // the canvas. To fix this we explicitly set Qt::WA_UnderMouse
01950     // if the mouse is inside the canvas.
01951     QWidget* w = this->getGLWidget();
01952     if (w && w->rect().contains(QCursor::pos()))
01953         w->setAttribute(Qt::WA_UnderMouse);
01954 
01955     if (!this->isCursorEnabled()) {
01956         this->setComponentCursor(SoQtCursor::getBlankCursor());
01957         return;
01958     }
01959 
01960     switch (modearg) {
01961     case NavigationStyle::IDLE:
01962     case NavigationStyle::INTERACT:
01963         if (isEditing())
01964             this->getWidget()->setCursor(this->editCursor);
01965         else
01966             this->setComponentCursor(SoQtCursor(SoQtCursor::DEFAULT));
01967         break;
01968 
01969     case NavigationStyle::DRAGGING:
01970     case NavigationStyle::SPINNING:
01971         this->setComponentCursor(SoQtCursor::getRotateCursor());
01972         break;
01973 
01974     case NavigationStyle::ZOOMING:
01975         {
01976             this->setComponentCursor(SoQtCursor::getZoomCursor());
01977         }   break;
01978 
01979     case NavigationStyle::SEEK_MODE:
01980     case NavigationStyle::SEEK_WAIT_MODE:
01981     case NavigationStyle::BOXZOOM:
01982         {
01983             SoQtCursor::CustomCursor custom;
01984             custom.dim.setValue(CROSS_WIDTH, CROSS_HEIGHT);
01985             custom.hotspot.setValue(CROSS_HOT_X, CROSS_HOT_Y);
01986             custom.bitmap = cross_bitmap;
01987             custom.mask = cross_mask_bitmap;
01988             this->setComponentCursor(SoQtCursor(&custom));
01989         }
01990         break;
01991 
01992     case NavigationStyle::PANNING:
01993         this->setComponentCursor(SoQtCursor::getPanCursor());
01994         break;
01995 
01996     case NavigationStyle::SELECTION:
01997         {
01998             SoQtCursor::CustomCursor custom;
01999             custom.dim.setValue(HAND_WITH, HAND_HEIGHT);
02000             custom.hotspot.setValue(HAND_HOT_X, HAND_HOT_Y);
02001             custom.bitmap = hand_bitmap;
02002             custom.mask = hand_mask_bitmap;
02003             this->setComponentCursor(SoQtCursor(&custom));
02004         }
02005         break;
02006 
02007     default: assert(0); break;
02008     }
02009 }
02010 
02011 void View3DInventorViewer::setEditing(SbBool edit) 
02012 {
02013     this->editing = edit; 
02014     this->setComponentCursor(SoQtCursor(SoQtCursor::DEFAULT));
02015     this->editCursor = QCursor();
02016 }
02017 
02018 void View3DInventorViewer::setEditingCursor (const SoQtCursor& cursor)
02019 {
02020     //Note: Coin caches the pointer to the CustomCursor instance with
02021     //the QCursor instance in a dictionary. So we must not store the
02022     //SoQtCursor object here but the QCursor object, otherwise we might
02023     //restore the wrong QCursor from the dictionary. 
02024     this->setComponentCursor(cursor);
02025     this->editCursor = this->getWidget()->cursor();
02026 }
02027 
02028 void View3DInventorViewer::setEditingCursor (const QCursor& cursor)
02029 {
02030     //Note: Coin caches the pointer to the CustomCursor instance with
02031     //the QCursor instance in a dictionary. So we must not store the
02032     //SoQtCursor object here but the QCursor object, otherwise we might
02033     //restore the wrong QCursor from the dictionary. 
02034     this->getWidget()->setCursor(cursor);
02035     this->editCursor = cursor;
02036 }
02037 
02038 void View3DInventorViewer::selectCB(void *viewer, SoPath *path)
02039 {
02040     ViewProvider* vp = static_cast<View3DInventorViewer*>(viewer)->getViewProviderByPath(path);
02041     if (vp && vp->useNewSelectionModel()) {
02042     }
02043 }
02044 
02045 void View3DInventorViewer::deselectCB(void *viewer, SoPath *path)
02046 {
02047     ViewProvider* vp = static_cast<View3DInventorViewer*>(viewer)->getViewProviderByPath(path);
02048     if (vp && vp->useNewSelectionModel()) {
02049     }
02050 }
02051 
02052 SoPath * View3DInventorViewer::pickFilterCB(void *viewer, const SoPickedPoint * pp)
02053 {
02054     ViewProvider* vp = static_cast<View3DInventorViewer*>(viewer)->getViewProviderByPath(pp->getPath());
02055     if (vp && vp->useNewSelectionModel()) {
02056         std::string e = vp->getElement(pp);
02057         vp->getSelectionShape(e.c_str());
02058         static char buf[513];
02059         snprintf(buf,512,"Hovered: %s (%f,%f,%f)"
02060                                    ,e.c_str()
02061                                    ,pp->getPoint()[0]
02062                                    ,pp->getPoint()[1]
02063                                    ,pp->getPoint()[2]);
02064 
02065         getMainWindow()->statusBar()->showMessage(QString::fromAscii(buf),3000);
02066     }
02067     return pp->getPath();
02068 }
02069 
02070 void View3DInventorViewer::addEventCallback(SoType eventtype, SoEventCallbackCB * cb, void* userdata)
02071 {
02072     pEventCallback->addEventCallback(eventtype, cb, userdata);
02073 }
02074 
02075 void View3DInventorViewer::removeEventCallback(SoType eventtype, SoEventCallbackCB * cb, void* userdata)
02076 {
02077     pEventCallback->removeEventCallback(eventtype, cb, userdata);
02078 }
02079 
02080 ViewProvider* View3DInventorViewer::getViewProviderByPath(SoPath * path) const
02081 {
02082     // FIXME Use the viewprovider map introduced for the selection
02083     for (std::set<ViewProvider*>::const_iterator it = _ViewProviderSet.begin(); it != _ViewProviderSet.end(); it++) {
02084         for (int i = 0; i<path->getLength();i++) {
02085             SoNode *node = path->getNode(i);
02086             if ((*it)->getRoot() == node) {
02087                 return (*it);
02088             }
02089         }
02090     }
02091 
02092     return 0;
02093 }
02094 
02095 ViewProvider* View3DInventorViewer::getViewProviderByPathFromTail(SoPath * path) const
02096 {
02097     // Make sure I'm the lowest LocHL in the pick path!
02098     for (int i = 0; i < path->getLength(); i++) {
02099         SoNode *node = path->getNodeFromTail(i);
02100         if (node->isOfType(SoSeparator::getClassTypeId())) {
02101             std::map<SoSeparator*,ViewProvider*>::const_iterator it = _ViewProviderMap.find(static_cast<SoSeparator*>(node));
02102             if (it != _ViewProviderMap.end()){
02103                 return it->second;
02104             }
02105          }
02106     }
02107 
02108     return 0;
02109 }
02110 
02111 std::vector<ViewProvider*> View3DInventorViewer::getViewProvidersOfType(const Base::Type& typeId) const
02112 {
02113     std::vector<ViewProvider*> views;
02114     for (std::set<ViewProvider*>::const_iterator it = _ViewProviderSet.begin(); it != _ViewProviderSet.end(); it++) {
02115         if ((*it)->getTypeId().isDerivedFrom(typeId)) {
02116             views.push_back(*it);
02117         }
02118     }
02119     return views;
02120 }
02121 
02122 void View3DInventorViewer::addFlag(Flag* item, FlagLayout::Position pos)
02123 {
02124     if (!_flaglayout) {
02125         _flaglayout = new FlagLayout(3);
02126         this->getGLWidget()->setLayout(_flaglayout);
02127     }
02128 
02129     item->setParent(this->getGLWidget());
02130     _flaglayout->addWidget(item, pos);
02131     item->show();
02132     this->scheduleRedraw();
02133 }

Generated on Wed Nov 23 19:00:57 2011 for FreeCAD by  doxygen 1.6.1