void WalkNavigationTool::buttonCallback(int,int buttonIndex,InputDevice::ButtonCallbackData* cbData) { if(cbData->newButtonState) // Button has just been pressed { /* Act depending on this tool's current state: */ if(isActive()) { /* Deactivate this tool: */ deactivate(); } else { /* Try activating this tool: */ if(activate()) { /* Store the center point for this navigation sequence: */ if(factory->centerOnActivation) centerPoint=factory->floorPlane.project(getMainViewer()->getHeadPosition()); /* Initialize the navigation transformation: */ preScale=Vrui::getNavigationTransformation(); translation=Vector::zero; rotation=Scalar(0); } } } }
void FPSNavigationTool::frame(void) { /* Act depending on this tool's current state: */ if(isActive()) { /* Calculate the change in mouse position: */ Point mousePos=calcMousePosition(); if(mousePos[0]!=lastMousePos[0]||mousePos[1]!=lastMousePos[1]||moveVelocity[0]!=Scalar(0)||moveVelocity[2]!=Scalar(0)) { angles[0]+=(mousePos[0]-lastMousePos[0])/factory->rotateFactor; angles[0]=Math::wrapRad(angles[0]); angles[1]+=(mousePos[1]-lastMousePos[1])/factory->rotateFactor; if(angles[1]<Math::rad(Scalar(-90))) angles[1]=Math::rad(Scalar(-90)); else if(angles[1]>Math::rad(Scalar(90))) angles[1]=Math::rad(Scalar(90)); /* Calculate the new orientation and move by the current velocity: */ ONTransform::Rotation yawT=ONTransform::Rotation::rotateY(angles[0]); ONTransform::Rotation rot=navFrame; rot*=ONTransform::Rotation::rotateX(angles[1]); rot*=yawT; pos+=yawT.inverseTransform(moveVelocity*getCurrentFrameTime()); /* Set the new navigation transformation: */ NavTransform nav=NavTransform::translateFromOriginTo(getMainViewer()->getHeadPosition()); nav*=NavTransform::rotate(rot); nav*=NavTransform::translateToOriginFrom(getMainViewer()->getHeadPosition()); nav*=NavTransform::translateFromOriginTo(pos); nav*=preScale; setNavigationTransformation(nav); if(mousePos[0]!=lastMousePos[0]||mousePos[1]!=lastMousePos[1]) { if(mouseAdapter!=0) { /* Warp the cursor back to the center of the window: */ mouseAdapter->getWindow()->setCursorPos(lastMousePos.getComponents()); } else lastMousePos=mousePos; } } } }
FlyNavigationTool::FlyNavigationTool(const ToolFactory* factory,const ToolInputAssignment& inputAssignment) :NavigationTool(factory,inputAssignment), viewer(0) { /* Retrieve the viewer associated with this menu tool: */ #if 0 int viewerIndex=configFile.retrieveValue<int>("./viewerIndex"); viewer=getViewer(viewerIndex); #else viewer=getMainViewer(); #endif }
void FPSNavigationTool::stopNavigating(void) { if(mouseAdapter!=0) { /* Disable mouse warping on the controlling window: */ mouseAdapter->setMousePosition(mouseAdapter->getWindow(),oldMousePos); mouseAdapter->getWindow()->setCursorPos(oldMousePos); mouseAdapter->getWindow()->showCursor(); } /* Reset the navigation transformation to only retain position and yaw angle: */ ONTransform::Rotation rot=navFrame; rot*=ONTransform::Rotation::rotateY(angles[0]); /* Set the new navigation transformation: */ NavTransform nav=NavTransform::translateFromOriginTo(getMainViewer()->getHeadPosition()); nav*=NavTransform::rotate(rot); nav*=NavTransform::translateToOriginFrom(getMainViewer()->getHeadPosition()); nav*=NavTransform::translateFromOriginTo(pos); nav*=preScale; setNavigationTransformation(nav); }
RayInputDeviceTool::RayInputDeviceTool(const ToolFactory* sFactory,const ToolInputAssignment& inputAssignment) :InputDeviceTool(sFactory,inputAssignment), viewer(0), dragger(getGlyphRenderer()->getGlyphSize(),factory->rotateFactor) { /* Retrieve the viewer associated with this tool: */ #if 0 int viewerIndex=configFile.retrieveValue<int>("./viewerIndex"); viewer=getViewer(viewerIndex); #else viewer=getMainViewer(); #endif }
RayScreenMenuTool::RayScreenMenuTool(const ToolFactory* factory,const ToolInputAssignment& inputAssignment) :MenuTool(factory,inputAssignment), viewer(0), insideWidget(false),widgetActive(false), dragging(false),draggedWidget(0) { /* Retrieve the viewer associated with this menu tool: */ #if 0 int viewerIndex=configFile.retrieveValue<int>("./viewerIndex"); viewer=getViewer(viewerIndex); #else viewer=getMainViewer(); #endif }
void MouseDialogNavigationTool::startDollying(void) { /* Calculate the dollying direction: */ if(mouseAdapter!=0&&mouseAdapter->getWindow()!=0) dollyDirection=mouseAdapter->getWindow()->getViewer()->getHeadPosition()-calcScreenCenter(); else dollyDirection=getMainViewer()->getHeadPosition()-calcScreenCenter(); dollyDirection.normalize(); /* Calculate initial motion position: */ motionStart=calcScreenPos(); preScale=getNavigationTransformation(); }
void HelicopterNavigationTool::buttonCallback(int,int buttonIndex,InputDevice::ButtonCallbackData* cbData) { /* Process based on which button was pressed: */ if(buttonIndex==0) { if(cbData->newButtonState) { /* Act depending on this tool's current state: */ if(isActive()) { /* Go back to original transformation: */ NavTransform nav=pre; nav*=NavTransform::translateToOriginFrom(currentPosition); nav*=post; setNavigationTransformation(nav); /* Deactivate this tool: */ deactivate(); } else { /* Try activating this tool: */ if(activate()) { /* Initialize the navigation: */ Vector x=Geometry::cross(getForwardDirection(),getUpDirection()); Vector y=Geometry::cross(getUpDirection(),x); pre=NavTransform::translateFromOriginTo(getMainViewer()->getHeadPosition()); pre*=NavTransform::rotate(Rotation::fromBaseVectors(x,y)); post=Geometry::invert(pre); post*=getNavigationTransformation(); currentPosition=Point::origin; currentOrientation=Rotation::identity; currentVelocity=Vector::zero; lastFrameTime=getApplicationTime(); } } } } else { /* Store the new state of the button: */ buttons[buttonIndex-1]=cbData->newButtonState; } }
void SixAxisSurfaceNavigationTool::initNavState(void) { /* Set up a physical navigation frame around the main viewer's current head position: */ headPos=getMainViewer()->getHeadPosition(); calcPhysicalFrame(headPos); /* Calculate the initial environment-aligned surface frame in navigation coordinates: */ surfaceFrame=getInverseNavigationTransformation()*physicalFrame; NavTransform newSurfaceFrame=surfaceFrame; /* Align the initial frame with the application's surface: */ AlignmentData ad(surfaceFrame,newSurfaceFrame,factory->probeSize,factory->maxClimb); align(ad,angles[0],angles[1],angles[2]); /* If flying is allowed and the initial surface frame was above the surface, lift it back up: */ Scalar z=newSurfaceFrame.inverseTransform(surfaceFrame.getOrigin())[2]; if(!factory->canFly||z<factory->probeSize) z=factory->probeSize; newSurfaceFrame*=NavTransform::translate(Vector(Scalar(0),Scalar(0),z)); /* Apply the initial navigation state: */ surfaceFrame=newSurfaceFrame; applyNavState(); }
void FPSNavigationTool::startNavigating(void) { /* Initialize the navigation state: */ if(mouseAdapter!=0) { /* Get the current cursor position in the controlling window: */ for(int i=0;i<2;++i) oldMousePos[i]=mouseAdapter->getMousePosition()[i]; /* Enable mouse warping on the controlling window: */ mouseAdapter->getWindow()->hideCursor(); mouseAdapter->getWindow()->getWindowCenterPos(lastMousePos.getComponents()); lastMousePos[2]=Scalar(0); mouseAdapter->getWindow()->setCursorPosWithAdjust(lastMousePos.getComponents()); mouseAdapter->setMousePosition(mouseAdapter->getWindow(),lastMousePos.getComponents()); /* Update the navigation frame on the off chance that the controlling window changed: */ ONTransform st=mouseAdapter->getWindow()->getVRScreen()->getScreenTransformation(); navFrame=st.getRotation(); pos=mouseAdapter->getWindow()->getViewer()->getHeadPosition(); } else { pos=getMainViewer()->getHeadPosition(); lastMousePos=calcMousePosition(); } angles[0]=angles[1]=Scalar(0); moveVelocity=Vector::zero; /* Calculate the prescale transformation: */ preScale=NavTransform::translateToOriginFrom(pos); preScale*=NavTransform::translateFromOriginTo(pos); preScale*=NavTransform::rotate(Geometry::invert(navFrame)); preScale*=NavTransform::translateToOriginFrom(pos); preScale*=getNavigationTransformation(); }
void SixAxisSurfaceNavigationTool::frame(void) { /* Act depending on this tool's current state: */ if(isActive()) { /* Use the average frame time as simulation time: */ Scalar dt=getCurrentFrameTime(); /* Update rotation angles based on current rotation valuator states: */ for(int i=0;i<3;++i) angles[i]=wrapAngle(angles[i]+getValuatorState(i+3)*factory->rotateFactors[i]*dt); if(angles[1]<Math::rad(Scalar(-90))) angles[1]=Math::rad(Scalar(-90)); else if(angles[1]>Math::rad(Scalar(90))) angles[1]=Math::rad(Scalar(90)); if(!factory->canRoll||factory->bankTurns) { Scalar targetRoll=factory->bankTurns?getValuatorState(3)*factory->rotateFactors[2]:Scalar(0); Scalar t=Math::exp(-factory->levelSpeed*dt); angles[2]=angles[2]*t+targetRoll*(Scalar(1)-t); if(Math::abs(angles[2]-targetRoll)<Scalar(1.0e-3)) angles[2]=targetRoll; } /* Calculate the new head position: */ Point newHeadPos=getMainViewer()->getHeadPosition(); /* Create a physical navigation frame around the new foot position: */ calcPhysicalFrame(newHeadPos); /* Calculate movement from head position change: */ Vector move=newHeadPos-headPos; headPos=newHeadPos; /* Add movement velocity based on the current translation valuator states: */ for(int i=0;i<3;++i) move[i]+=getValuatorState(i)*factory->translateFactors[i]*dt; /* Transform the movement vector from physical space to the physical navigation frame: */ move=physicalFrame.inverseTransform(move); /* Rotate by the current azimuth and elevation angles: */ move=Rotation::rotateX(-angles[1]).transform(move); move=Rotation::rotateZ(-angles[0]).transform(move); /* Move the surface frame: */ NavTransform newSurfaceFrame=surfaceFrame; newSurfaceFrame*=NavTransform::translate(move); /* Re-align the surface frame with the surface: */ Point initialOrigin=newSurfaceFrame.getOrigin(); Rotation initialOrientation=newSurfaceFrame.getRotation(); AlignmentData ad(surfaceFrame,newSurfaceFrame,factory->probeSize,factory->maxClimb); align(ad); if(!factory->fixAzimuth) { /* Have the azimuth angle track changes in the surface frame's rotation: */ Rotation rot=Geometry::invert(initialOrientation)*newSurfaceFrame.getRotation(); rot.leftMultiply(Rotation::rotateFromTo(rot.getDirection(2),Vector(0,0,1))); Vector x=rot.getDirection(0); angles[0]=wrapAngle(angles[0]+Math::atan2(x[1],x[0])); } /* If flying is allowed and the initial surface frame was above the surface, lift it back up: */ Scalar z=newSurfaceFrame.inverseTransform(initialOrigin)[2]; if(!factory->canFly||z<factory->probeSize) z=factory->probeSize; newSurfaceFrame*=NavTransform::translate(Vector(Scalar(0),Scalar(0),z)); /* Apply the newly aligned surface frame: */ surfaceFrame=newSurfaceFrame; applyNavState(); /* Deactivate the tool if it is done: */ if(numActiveAxes==0&&Math::abs(angles[2])<Math::Constants<Scalar>::epsilon) deactivate(); else { /* Request another frame: */ scheduleUpdate(getApplicationTime()+1.0/125.0); } } }
void MouseNavigationTool::valuatorCallback(int,InputDevice::ValuatorCallbackData* cbData) { currentValue=Scalar(cbData->newValuatorValue); if(currentValue!=Scalar(0)) { /* Act depending on this tool's current state: */ switch(navigationMode) { case IDLE: case SPINNING: /* Try activating this tool: */ if(navigationMode==SPINNING||activate()) { if(dolly) { /* Calculate the dollying direction: */ if(mouseAdapter!=0) dollyDirection=mouseAdapter->getWindow()->getViewer()->getHeadPosition()-calcScreenCenter(); else dollyDirection=getMainViewer()->getHeadPosition()-calcScreenCenter(); dollyDirection.normalize(); /* Initialize the wheel dollying factor: */ currentWheelScale=Scalar(1); preScale=getNavigationTransformation(); /* Go to wheel dollying mode: */ navigationMode=DOLLYING_WHEEL; } else { /* Calculate the scaling center: */ screenCenter=calcScreenCenter(); /* Initialize the wheel scaling factor: */ currentWheelScale=Scalar(1); preScale=NavTrackerState::translateFromOriginTo(screenCenter); postScale=NavTrackerState::translateToOriginFrom(screenCenter); postScale*=getNavigationTransformation(); /* Go to wheel scaling mode: */ navigationMode=SCALING_WHEEL; } } break; default: /* This can definitely happen; just ignore the event */ break; } } else { /* Act depending on this tool's current state: */ switch(navigationMode) { case DOLLYING_WHEEL: case SCALING_WHEEL: /* Deactivate this tool: */ deactivate(); /* Go to idle mode: */ navigationMode=IDLE; break; default: /* This can definitely happen; just ignore the event */ break; } } }
void WalkNavigationTool::frame(void) { /* Act depending on this tool's current state: */ if(isActive()) { /* Get the current head position and viewing direction: */ Point headPos=getMainViewer()->getHeadPosition(); Vector viewDir=getMainViewer()->getViewDirection(); /* Project head position and viewing direction onto floor plane: */ headPos=factory->floorPlane.project(headPos); viewDir=factory->floorPlane.project(viewDir); viewDir.normalize(); /* Calculate the movement direction and speed: */ Vector moveDir=centerPoint-headPos; Scalar moveDirLen=moveDir.mag(); Scalar speed=Scalar(0); if(moveDirLen>=factory->outerRadius) speed=factory->moveSpeed; else if(moveDirLen>factory->innerRadius) speed=factory->moveSpeed*(moveDirLen-factory->innerRadius)/(factory->outerRadius-factory->innerRadius); moveDir*=speed/moveDirLen; /* Calculate the rotation speed: */ Scalar viewAngleCos=viewDir*factory->centerViewDirection; Scalar viewAngle; if(viewAngleCos>Scalar(1)-Math::Constants<Scalar>::epsilon) viewAngle=Scalar(0); else if(viewAngleCos<Scalar(-1)+Math::Constants<Scalar>::epsilon) viewAngle=Math::Constants<Scalar>::pi; else viewAngle=Math::acos(viewAngleCos); Scalar rotateAngle=Scalar(0); if(viewAngle>=factory->outerAngle) rotateAngle=factory->rotateSpeed; else if(viewAngle>factory->innerAngle) rotateAngle=factory->rotateSpeed*(viewAngle-factory->innerAngle)/(factory->outerAngle-factory->innerAngle); Vector x=Geometry::cross(factory->centerViewDirection,factory->floorPlane.getNormal()); if(viewDir*x<Scalar(0)) rotateAngle=-rotateAngle; /* Accumulate the transformation: */ rotation+=rotateAngle*getFrameTime(); if(rotation<-Math::Constants<Scalar>::pi) rotation+=Scalar(2)*Math::Constants<Scalar>::pi; else if(rotation>=Math::Constants<Scalar>::pi) rotation-=Scalar(2)*Math::Constants<Scalar>::pi; NavTransform::Rotation rot=NavTransform::Rotation::rotateAxis(factory->floorPlane.getNormal(),rotation); translation+=rot.inverseTransform(moveDir*getFrameTime()); /* Set the navigation transformation: */ NavTransform nav=NavTransform::identity; nav*=Vrui::NavTransform::translateFromOriginTo(centerPoint); nav*=Vrui::NavTransform::rotate(rot); nav*=Vrui::NavTransform::translateToOriginFrom(centerPoint); nav*=Vrui::NavTransform::translate(translation); nav*=preScale; setNavigationTransformation(nav); } }
void ViewerConfiguration::buildViewerConfigurationControls(void) { /* Build the graphical user interface: */ const GLMotif::StyleSheet& ss=*getUiStyleSheet(); dialogWindow=new GLMotif::PopupWindow("ViewerConfigurationDialog",getWidgetManager(),"Viewer Configuration"); dialogWindow->setHideButton(true); dialogWindow->setResizableFlags(true,false); GLMotif::RowColumn* viewerConfiguration=new GLMotif::RowColumn("ViewerConfiguration",dialogWindow,false); viewerConfiguration->setOrientation(GLMotif::RowColumn::VERTICAL); viewerConfiguration->setPacking(GLMotif::RowColumn::PACK_TIGHT); viewerConfiguration->setNumMinorWidgets(2); /* Create a drop-down menu to select a viewer: */ new GLMotif::Label("ViewerLabel",viewerConfiguration,"Viewer"); viewerMenu=new GLMotif::DropdownBox("ViewerMenu",viewerConfiguration); int mainViewerIndex=0; for(int viewerIndex=0;viewerIndex<getNumViewers();++viewerIndex) { Viewer* viewer=getViewer(viewerIndex); viewerMenu->addItem(viewer->getName()); if(viewer==getMainViewer()) mainViewerIndex=viewerIndex; } viewerMenu->setSelectedItem(mainViewerIndex); viewerMenu->getValueChangedCallbacks().add(this,&ViewerConfiguration::viewerMenuCallback); /* Calculate an appropriate slider range and granularity: */ Scalar sliderRange=Scalar(18)*factory->configUnit.getInchFactor(); // Slider range is at least 18" Scalar sliderRangeFactor=Math::pow(Scalar(10),Math::floor(Math::log10(sliderRange))); sliderRange=Math::ceil(sliderRange/sliderRangeFactor)*sliderRangeFactor; Scalar sliderStep=Scalar(0.01)*factory->configUnit.getInchFactor(); // Slider granularity is at most 0.01" int sliderStepDigits=int(Math::floor(Math::log10(sliderStep))); Scalar sliderStepFactor=Math::pow(Scalar(10),Scalar(sliderStepDigits)); sliderStep=Math::floor(sliderStep/sliderStepFactor)*sliderStepFactor; sliderStepDigits=sliderStepDigits<0?-sliderStepDigits:0; /* Create three sliders to set the mono eye position: */ new GLMotif::Label("MonoEyePosLabel",viewerConfiguration,"Mono Eye"); GLMotif::RowColumn* monoEyePosBox=new GLMotif::RowColumn("MonoEyePosBox",viewerConfiguration,false); monoEyePosBox->setPacking(GLMotif::RowColumn::PACK_GRID); for(int i=0;i<3;++i) { char epsName[14]="EyePosSlider "; epsName[12]=char(i+'0'); eyePosSliders[0][i]=new GLMotif::TextFieldSlider(epsName,monoEyePosBox,7,ss.fontHeight*10.0f); eyePosSliders[0][i]->getTextField()->setFieldWidth(6); eyePosSliders[0][i]->getTextField()->setPrecision(sliderStepDigits); eyePosSliders[0][i]->getTextField()->setFloatFormat(GLMotif::TextField::FIXED); eyePosSliders[0][i]->setSliderMapping(GLMotif::TextFieldSlider::LINEAR); eyePosSliders[0][i]->setValueType(GLMotif::TextFieldSlider::FLOAT); eyePosSliders[0][i]->setValueRange(-sliderRange,sliderRange,sliderStep); eyePosSliders[0][i]->getValueChangedCallbacks().add(this,&ViewerConfiguration::eyePosSliderCallback,i); } monoEyePosBox->manageChild(); /* Create a slider to set the eye separation distance: */ new GLMotif::Label("EyeDistLabel",viewerConfiguration,"Eye Distance"); eyeDistanceSlider=new GLMotif::TextFieldSlider("EyeDistanceSlider",viewerConfiguration,7,ss.fontHeight*10.0f); eyeDistanceSlider->getTextField()->setFieldWidth(6); eyeDistanceSlider->getTextField()->setPrecision(sliderStepDigits); eyeDistanceSlider->getTextField()->setFloatFormat(GLMotif::TextField::FIXED); eyeDistanceSlider->setSliderMapping(GLMotif::TextFieldSlider::LINEAR); eyeDistanceSlider->setValueType(GLMotif::TextFieldSlider::FLOAT); eyeDistanceSlider->setValueRange(sliderStep*Scalar(10),sliderRange,sliderStep); eyeDistanceSlider->getValueChangedCallbacks().add(this,&ViewerConfiguration::eyeDistanceSliderCallback); /* Create two triples of sliders to set the left and right eye positions: */ for(int eyeIndex=1;eyeIndex<3;++eyeIndex) { /* Create a separator: */ new GLMotif::Blind(eyeIndex==1?"Blind1":"Blind2",viewerConfiguration); new GLMotif::Separator(eyeIndex==1?"Separator1":"Separator2",viewerConfiguration,GLMotif::Separator::HORIZONTAL,ss.fontHeight,GLMotif::Separator::LOWERED); /* Create three sliders to set the left or right eye position: */ new GLMotif::Label(eyeIndex==1?"LeftEyePosLabel":"RightEyePosLabel",viewerConfiguration,eyeIndex==1?"Left Eye":"Right Eye"); GLMotif::RowColumn* eyePosBox=new GLMotif::RowColumn(eyeIndex==1?"LeftEyePosBox":"RightEyePosBox",viewerConfiguration,false); eyePosBox->setPacking(GLMotif::RowColumn::PACK_GRID); for(int i=0;i<3;++i) { char epsName[14]="EyePosSlider "; epsName[12]=char(eyeIndex*3+i+'0'); eyePosSliders[eyeIndex][i]=new GLMotif::TextFieldSlider(epsName,eyePosBox,7,ss.fontHeight*10.0f); eyePosSliders[eyeIndex][i]->getTextField()->setFieldWidth(6); eyePosSliders[eyeIndex][i]->getTextField()->setPrecision(sliderStepDigits); eyePosSliders[eyeIndex][i]->getTextField()->setFloatFormat(GLMotif::TextField::FIXED); eyePosSliders[eyeIndex][i]->setSliderMapping(GLMotif::TextFieldSlider::LINEAR); eyePosSliders[eyeIndex][i]->setValueType(GLMotif::TextFieldSlider::FLOAT); eyePosSliders[eyeIndex][i]->setValueRange(-sliderRange,sliderRange,sliderStep); eyePosSliders[eyeIndex][i]->getValueChangedCallbacks().add(this,&ViewerConfiguration::eyePosSliderCallback,eyeIndex*3+i); } eyePosBox->manageChild(); } viewerConfiguration->manageChild(); /* Initialize vislet state and GUI: */ setViewer(getViewer(mainViewerIndex)); }
void WalkNavigationTool::frame(void) { /* Act depending on this tool's current state: */ if(isActive()) { /* Calculate azimuth angle change based on the current viewing direction: */ Vector viewDir=getMainViewer()->getViewDirection(); viewDir-=getUpDirection()*((viewDir*getUpDirection())/Geometry::sqr(getUpDirection())); Scalar viewDir2=Geometry::sqr(viewDir); if(viewDir2!=Scalar(0)) { /* Calculate the rotation speed: */ Scalar viewAngleCos=(viewDir*factory->centerViewDirection)/Math::sqrt(viewDir2); Scalar viewAngle; if(viewAngleCos>Scalar(1)-Math::Constants<Scalar>::epsilon) viewAngle=Scalar(0); else if(viewAngleCos<Scalar(-1)+Math::Constants<Scalar>::epsilon) viewAngle=Math::Constants<Scalar>::pi; else viewAngle=Math::acos(viewAngleCos); Scalar rotateSpeed=Scalar(0); if(viewAngle>=factory->outerAngle) rotateSpeed=factory->rotateSpeed; else if(viewAngle>factory->innerAngle) rotateSpeed=factory->rotateSpeed*(viewAngle-factory->innerAngle)/(factory->outerAngle-factory->innerAngle); Vector x=factory->centerViewDirection^getUpDirection(); if(viewDir*x<Scalar(0)) rotateSpeed=-rotateSpeed; /* Update the accumulated rotation angle: */ azimuth+=rotateSpeed*getFrameTime(); if(azimuth<-Math::Constants<Scalar>::pi) azimuth+=Scalar(2)*Math::Constants<Scalar>::pi; else if(azimuth>=Math::Constants<Scalar>::pi) azimuth-=Scalar(2)*Math::Constants<Scalar>::pi; } /* Calculate the movement direction and speed: */ Point footPos=projectToFloor(getMainViewer()->getHeadPosition()); Vector moveDir=centerPoint-footPos; Scalar moveDirLen=moveDir.mag(); Scalar speed=Scalar(0); if(moveDirLen>=factory->outerRadius) speed=factory->moveSpeed; else if(moveDirLen>factory->innerRadius) speed=factory->moveSpeed*(moveDirLen-factory->innerRadius)/(factory->outerRadius-factory->innerRadius); moveDir*=speed/moveDirLen; /* Accumulate the transformation: */ NavTransform::Rotation rot=NavTransform::Rotation::rotateAxis(getUpDirection(),azimuth); translation+=rot.inverseTransform(moveDir*getFrameTime()); /* Set the navigation transformation: */ NavTransform nav=NavTransform::identity; nav*=Vrui::NavTransform::translateFromOriginTo(centerPoint); nav*=Vrui::NavTransform::rotate(rot); nav*=Vrui::NavTransform::translateToOriginFrom(centerPoint); nav*=Vrui::NavTransform::translate(translation); nav*=preScale; setNavigationTransformation(nav); if(speed!=Scalar(0)) { /* Request another frame: */ scheduleUpdate(getApplicationTime()+1.0/125.0); } } }