Point TrackballNavigationTool::calcTrackballPosition(void) const
	{
	/* Get device ray equation: */
	Ray ray=getButtonDeviceRay(0);
	
	/* Intersect ray with trackball sphere: */
	Vector d=getDisplayCenter()-ray.getOrigin();
	Scalar dLen2=Geometry::sqr(d);
	Scalar ph=ray.getDirection()*d;
	Scalar radius=getDisplaySize();
	Scalar det=Math::sqr(ph)+Math::sqr(radius)-dLen2;
	if(det>=Scalar(0))
		{
		/* Find first intersection of ray with sphere (even if behind start point): */
		det=Math::sqrt(det);
		Scalar lambda=ph-det;
		return ray(lambda);
		}
	else
		{
		/* Find closest point on sphere to ray: */
		Vector ctop=ray.getDirection()*((d*ray.getDirection())/Geometry::sqr(ray.getDirection()))-d;
		ctop*=radius/Geometry::mag(ctop);
		return getDisplayCenter()+ctop;
		}
	}
void TrackballNavigationTool::frame(void)
	{
	/* Act depending on this tool's current state: */
	if(isActive())
		{
		/* Calculate new interaction position: */
		Point dragPosition=calcTrackballPosition();
		
		/* Calculate incremental transformation from old to new point: */
		Vector v1=lastDragPosition-getDisplayCenter();
		Vector v2=dragPosition-getDisplayCenter();
		Vector axis=Geometry::cross(v1,v2);
		Scalar axisLen=Geometry::mag(axis);
		if(axisLen!=Scalar(0))
			{
			/* Calculate rotation angle: */
			axis/=axisLen;
			Scalar angle=Math::acos((v1*v2)/(Geometry::mag(v1)*Geometry::mag(v2)))*factory->rotateFactor;
			
			/* Compose new navigation transformation: */
			NavTrackerState navigation=NavTrackerState::rotateAround(getDisplayCenter(),NavTrackerState::Rotation::rotateAxis(axis,angle));
			navigation*=getNavigationTransformation();
			
			/* Update Vrui's navigation transformation: */
			setNavigationTransformation(navigation);
			}
		
		lastDragPosition=dragPosition;
		}
	}
Exemple #3
0
void ScaleBar::pointerButtonDown(GLMotif::Event& event)
	{
	Scalar newScale=currentScale;
	
	/* Check if the event happened in the left or right corner: */
	float relEventPos=(event.getWidgetPoint().getPoint()[0]-getInterior().origin[0])/getInterior().size[0];
	if(relEventPos<=0.333f)
		{
		/* Calculate the next smaller quasi-binary scale factor: */
		newScale=Scalar(getSmallerQuasiBinary(currentScale));
		}
	else if(relEventPos>=0.667f)
		{
		/* Calculate the next bigger quasi-binary scale factor: */
		newScale=Scalar(getBiggerQuasiBinary(currentScale));
		}
	
	if(newScale!=currentScale&&activateNavigationTool(reinterpret_cast<const Tool*>(this)))
		{
		/* Adjust the navigation transformation: */
		Scalar newNavScale;
		const Geometry::LinearUnit& unit=getCoordinateManager()->getUnit();
		if(unit.isImperial())
			{
			/* Calculate scale factor through imperial units: */
			newNavScale=getInchFactor()*newScale/unit.getInchFactor();
			}
		else
			{
			/* Calculate scale factor through metric units: */
			newNavScale=getMeterFactor()*newScale/unit.getMeterFactor();
			}
		
		/* Get the current navigation transformation and calculate the display center position in navigation coordinates: */
		const NavTransform& nav=getNavigationTransformation();
		Point center=nav.inverseTransform(getDisplayCenter());
		
		/* Create the new navigation transformation: */
		NavTransform newNav=NavTransform(nav.getTranslation(),nav.getRotation(),newNavScale);
		newNav.leftMultiply(NavTransform::translate(getDisplayCenter()-newNav.transform(center)));
		setNavigationTransformation(newNav);
		
		deactivateNavigationTool(reinterpret_cast<const Tool*>(this));
		currentScale=newScale;
		
		/* Update the scale bar: */
		calcSize(newNav);
		
		/* Resize the widget so that the clicked point stays in the same place: */
		GLMotif::Vector newSize=calcNaturalSize();
		GLfloat newInteriorWidth=newSize[0]-2.0f*getBorderWidth();
		GLfloat newOrigin=event.getWidgetPoint().getPoint()[0]-newInteriorWidth*relEventPos-getBorderWidth();
		resize(GLMotif::Box(GLMotif::Vector(newOrigin,0.0f,0.0f),newSize));
		}
	}
bool ViewpointFileNavigationTool::navigate(Scalar parameter)
	{
	/* Find the spline segment containing the given parameter: */
	int l=0;
	int r=splines.size();
	while(r-l>1)
		{
		int m=(l+r)>>1;
		if(parameter>=splines[m].t[0])
			l=m;
		else
			r=m;
		}
	const SplineSegment& s=splines[l];
	if(parameter>=s.t[0]&&parameter<=s.t[1])
		{
		/* Evaluate the spline segment at the current time: */
		Scalar t=(parameter-s.t[0])/(s.t[1]-s.t[0]);
		ControlPoint cp[6];
		for(int i=0;i<3;++i)
			interpolate(s.p[i],s.p[i+1],t,cp[i]);
		for(int i=0;i<2;++i)
			interpolate(cp[i],cp[i+1],t,cp[3+i]);
		interpolate(cp[3],cp[4],t,cp[5]);

		/* Compute the appropriate navigation transformation from the next viewpoint: */
		NavTransform nav=NavTransform::identity;
		nav*=NavTransform::translateFromOriginTo(getDisplayCenter());
		nav*=NavTransform::rotate(Rotation::fromBaseVectors(Geometry::cross(getForwardDirection(),getUpDirection()),getForwardDirection()));
		nav*=NavTransform::scale(getDisplaySize()/Math::exp(cp[5].size)); // Scales are interpolated logarithmically
		nav*=NavTransform::rotate(Geometry::invert(Rotation::fromBaseVectors(Geometry::cross(cp[5].forward,cp[5].up),cp[5].forward)));
		nav*=NavTransform::translateToOriginFrom(cp[5].center);
		
		if(isActive())
			{
			/* Set the viewpoint: */
			setNavigationTransformation(nav);
			}
		else if(activate())
			{
			/* Set the viewpoint: */
			setNavigationTransformation(nav);
			
			/* Deactivate again: */
			deactivate();
			}
		
		nextViewpointIndex=l+1;
		return true;
		}
	else
		{
		/* Stop animating; spline is over: */
		nextViewpointIndex=0;
		return false;
		}
	}
void ViewpointFileNavigationTool::buttonCallback(int,InputDevice::ButtonCallbackData* cbData)
	{
	if(cbData->newButtonState) // Activation button has just been pressed
		{
		#if 0
		/* Set the next saved viewpoint if the tool can be activated: */
		if(!viewpoints.empty()&&activate())
			{
			/* Compute the appropriate navigation transformation from the next viewpoint: */
			const Viewpoint& v=viewpoints[nextViewpointIndex];
			NavTransform nav=NavTransform::identity;
			nav*=NavTransform::translateFromOriginTo(getDisplayCenter());
			nav*=NavTransform::rotate(Rotation::fromBaseVectors(Geometry::cross(getForwardDirection(),getUpDirection()),getForwardDirection()));
			nav*=NavTransform::scale(getDisplaySize()/Math::exp(v.size)); // Scales are interpolated logarithmically
			nav*=NavTransform::rotate(Geometry::invert(Rotation::fromBaseVectors(Geometry::cross(v.forward,v.up),v.forward)));
			nav*=NavTransform::translateToOriginFrom(v.center);
			
			/* Set the viewpoint: */
			setNavigationTransformation(nav);
			
			/* Go to the next viewpoint: */
			++nextViewpointIndex;
			if(nextViewpointIndex==viewpoints.size())
				nextViewpointIndex=0U;
			
			/* Deactivate the tool: */
			deactivate();
			}
		#else
		/* Start animating the viewpoint if there are spline segments and the tool can be activated: */
		if(!splines.empty())
			{
			if(paused&&activate())
				{
				/* Unpause the animation: */
				paused=false;
				parameter-=Scalar(getFrameTime())*speed;
				}
			else if(isActive())
				{
				/* Pause the animation: */
				paused=true;
				deactivate();
				}
			else if(activate())
				{
				/* Animate from the beginning: */
				paused=false;
				parameter=splines.front().t[0]-Scalar(getFrameTime())*speed;
				if(positionSlider!=0)
					positionSlider->setValue(parameter);
				}
			}
		#endif
		}
	}
MouseDialogNavigationTool::MouseDialogNavigationTool(const ToolFactory* factory,const ToolInputAssignment& inputAssignment)
	:NavigationTool(factory,inputAssignment),
	 mouseAdapter(0),
	 navigationDialogPopup(0),
	 navigationMode(ROTATING),
	 spinning(false),
	 showScreenCenter(false)
	{
	/* Find the mouse input device adapter controlling the input device: */
	mouseAdapter=dynamic_cast<InputDeviceAdapterMouse*>(getInputDeviceManager()->findInputDeviceAdapter(getDevice(0)));
	
	/* Create the tool's GUI: */
	navigationDialogPopup=new GLMotif::PopupWindow("NavigationDialogPopup",getWidgetManager(),"Mouse Navigation Dialog");
	
	GLMotif::RowColumn* navigationDialog=new GLMotif::RowColumn("NavigationDialog",navigationDialogPopup,false);
	
	GLMotif::RadioBox* navigationModes=new GLMotif::RadioBox("NavigationModes",navigationDialog,false);
	navigationModes->setOrientation(GLMotif::RowColumn::VERTICAL);
	navigationModes->setPacking(GLMotif::RowColumn::PACK_GRID);
	navigationModes->setSelectionMode(GLMotif::RadioBox::ALWAYS_ONE);
	
	navigationModes->addToggle("Rotate");
	navigationModes->addToggle("Pan");
	navigationModes->addToggle("Dolly");
	navigationModes->addToggle("Scale");
	
	switch(navigationMode)
		{
		case ROTATING:
			navigationModes->setSelectedToggle(0);
			break;
		
		case PANNING:
			navigationModes->setSelectedToggle(1);
			break;
		
		case DOLLYING:
			navigationModes->setSelectedToggle(2);
			break;
		
		case SCALING:
			navigationModes->setSelectedToggle(3);
			break;
		}
	navigationModes->getValueChangedCallbacks().add(this,&MouseDialogNavigationTool::navigationModesValueChangedCallback);
	navigationModes->manageChild();
	
	GLMotif::ToggleButton* showScreenCenterToggle=new GLMotif::ToggleButton("ShowScreenCenterToggle",navigationDialog,"Show Screen Center");
	showScreenCenterToggle->setToggle(showScreenCenter);
	showScreenCenterToggle->getValueChangedCallbacks().add(this,&MouseDialogNavigationTool::showScreenCenterToggleValueChangedCallback);
	
	navigationDialog->manageChild();
	
	/* Pop up the navigation dialog: */
	popupPrimaryWidget(navigationDialogPopup,getNavigationTransformation().transform(getDisplayCenter()));
	}
TrackerState SixAxisTransformToolFactory::Configuration::getHomePosition(void) const
{
    if(homePosition.isSpecified())
    {
        /* Return the configured home position: */
        return homePosition.getValue();
    }
    else
    {
        /* Calculate the home position from current display center and environment orientation: */
        Vector x=getForwardDirection()^getUpDirection();
        Vector y=getUpDirection()^x;
        return TrackerState(getDisplayCenter()-Point::origin,Rotation::fromBaseVectors(x,y));
    }
}
SixAxisTransformToolFactory::Configuration::Configuration(void)
	:translateFactor(getDisplaySize()/Scalar(3)),
	 translations(Vector::zero),
	 rotateFactor(Scalar(180)),
	 rotations(Vector::zero),
	 followDisplayCenter(true),
	 homePosition(getDisplayCenter()),
	 deviceGlyphType("Cone"),
	 deviceGlyphMaterial(GLMaterial::Color(0.5f,0.5f,0.5f),GLMaterial::Color(1.0f,1.0f,1.0f),25.0f)
	{
	/* Initialize translation vectors and scaled rotation axes: */
	for(int i=0;i<3;++i)
		translations[i][i]=Scalar(1);
	for(int i=0;i<3;++i)
		rotations[i][i]=Scalar(1);
	}
Exemple #9
0
Point RayMenuTool::calcHotSpot(void) const
	{
	if(isUseEyeRay()||interactionDevice->isRayDevice())
		{
		/* Find the intersection point of the interaction ray and a screen: */
		std::pair<VRScreen*,Scalar> si=findScreen(GUIInteractor::getRay());
		if(si.first!=0)
			return GUIInteractor::getRay()(si.second);
		else
			return getDisplayCenter();
		}
	else
		{
		/* Return a position in front of the input device: */
		return GUIInteractor::getRay()(factory->initialMenuOffset);
		}
	}
SixAxisNavigationToolFactory::Configuration::Configuration(void)
	:translateFactor(getDisplaySize()/Scalar(3)),
	 translations(Vector::zero),
	 rotateFactor(Scalar(180)),
	 rotations(Vector::zero),
	 zoomFactor(Scalar(1)),
	 followDisplayCenter(false),
	 navigationCenter(getDisplayCenter()),
	 invertNavigation(false),
	 showNavigationCenter(true)
	{
	/* Initialize translation vectors and scaled rotation axes: */
	for(int i=0;i<3;++i)
		translations[i][i]=Scalar(1);
	for(int i=0;i<3;++i)
		rotations[i][i]=Scalar(1);
	}
void SixAxisNavigationTool::frame(void)
	{
	if(isActive())
		{
		/* Assemble translation from translation vectors and current valuator values: */
		Vector translation=Vector::zero;
		for(int i=0;i<3;++i)
			translation+=translations[i]*Scalar(getValuatorState(i));
		translation*=getCurrentFrameTime();
		
		/* Assemble rotation from scaled rotation axes and current valuator values: */
		Vector rotation=Vector::zero;
		for(int i=0;i<3;++i)
			rotation+=rotations[i]*Scalar(getValuatorState(3+i));
		rotation*=getCurrentFrameTime();
		
		/* Calculate incremental zoom factor: */
		Scalar zoom=config.zoomFactor*Scalar(getValuatorState(6))*getCurrentFrameTime();
		
		/* Apply proper navigation mode: */
		if(config.invertNavigation)
			{
			translation=-translation;
			rotation=-rotation;
			zoom=-zoom;
			}
		
		/* Calculate an incremental transformation based on the translation and rotation: */
		NavTrackerState deltaT=NavTrackerState::translateFromOriginTo(config.followDisplayCenter?getDisplayCenter():config.navigationCenter);
		deltaT*=NavTrackerState::translate(translation);
		deltaT*=NavTrackerState::rotate(NavTrackerState::Rotation::rotateScaledAxis(rotation));
		deltaT*=NavTrackerState::scale(Math::exp(-zoom));
		deltaT*=NavTrackerState::translateToOriginFrom(config.followDisplayCenter?getDisplayCenter():config.navigationCenter);
		
		/* Update the accumulated transformation: */
		navTransform.leftMultiply(deltaT);
		navTransform.renormalize();
		
		/* Update the navigation transformation: */
		setNavigationTransformation(navTransform);
		
		/* Request another frame: */
		scheduleUpdate(getApplicationTime()+1.0/125.0);
		}
	}
void SixAxisNavigationTool::display(GLContextData& contextData) const
	{
	if(config.showNavigationCenter&&isActive())
		{
		/* Set up OpenGL state: */
		glPushAttrib(GL_DEPTH_BUFFER_BIT|GL_ENABLE_BIT|GL_LINE_BIT);
		glDisable(GL_LIGHTING);
		glDepthFunc(GL_LEQUAL);
		
		/* Calculate colors to draw the crosshairs: */
		Color bgColor=getBackgroundColor();
		Color fgColor;
		for(int i=0;i<3;++i)
			fgColor[i]=1.0f-bgColor[i];
		fgColor[3]=bgColor[3];
		
		/* Go to crosshair space: */
		glPushMatrix();
		ONTransform trans=calcHUDTransform(config.followDisplayCenter?getDisplayCenter():config.navigationCenter);
		glMultMatrix(trans);
		
		glLineWidth(3.0f);
		glBegin(GL_LINES);
		glColor(bgColor);
		glVertex2d(-getDisplaySize(),0.0);
		glVertex2d(getDisplaySize(),0.0);
		glVertex2d(0.0,-getDisplaySize());
		glVertex2d(0.0,getDisplaySize());
		glEnd();
		
		glLineWidth(1.0f);
		glBegin(GL_LINES);
		glColor(fgColor);
		glVertex2d(-getDisplaySize(),0.0);
		glVertex2d(getDisplaySize(),0.0);
		glVertex2d(0.0,-getDisplaySize());
		glVertex2d(0.0,getDisplaySize());
		glEnd();
		
		glPopMatrix();
		
		/* Restore OpenGL state: */
		glPopAttrib();
		}
	}
WalkNavigationToolFactory::WalkNavigationToolFactory(ToolManager& toolManager)
	:ToolFactory("WalkNavigationTool",toolManager),
	 floorPlane(getFloorPlane()),
	 centerOnActivation(false),
	 centerPoint(getDisplayCenter()),
	 moveSpeed(getDisplaySize()),
	 innerRadius(getDisplaySize()*Scalar(0.5)),outerRadius(getDisplaySize()*Scalar(0.75)),
	 centerViewDirection(getForwardDirection()),
	 rotateSpeed(Math::rad(Scalar(120))),
	 innerAngle(Math::rad(Scalar(30))),outerAngle(Math::rad(Scalar(120))),
	 drawMovementCircles(true),
	 movementCircleColor(0.0f,1.0f,0.0f)
	{
	/* Initialize tool layout: */
	layout.setNumDevices(1);
	layout.setNumButtons(0,1);
	
	/* Insert class into class hierarchy: */
	ToolFactory* navigationToolFactory=toolManager.loadClass("NavigationTool");
	navigationToolFactory->addChildClass(this);
	addParentClass(navigationToolFactory);
	
	/* Load class settings: */
	Misc::ConfigurationFileSection cfs=toolManager.getToolClassSection(getClassName());
	floorPlane=cfs.retrieveValue<Plane>("./floorPlane",floorPlane);
	floorPlane.normalize();
	centerOnActivation=cfs.retrieveValue<bool>("./centerOnActivation",centerOnActivation);
	centerPoint=cfs.retrieveValue<Point>("./centerPoint",centerPoint);
	centerPoint=floorPlane.project(centerPoint);
	moveSpeed=cfs.retrieveValue<Scalar>("./moveSpeed",moveSpeed);
	innerRadius=cfs.retrieveValue<Scalar>("./innerRadius",innerRadius);
	outerRadius=cfs.retrieveValue<Scalar>("./outerRadius",outerRadius);
	centerViewDirection=cfs.retrieveValue<Vector>("./centerViewDirection",centerViewDirection);
	centerViewDirection=floorPlane.project(centerViewDirection);
	centerViewDirection.normalize();
	rotateSpeed=Math::rad(cfs.retrieveValue<Scalar>("./rotateSpeed",Math::deg(rotateSpeed)));
	innerAngle=Math::rad(cfs.retrieveValue<Scalar>("./innerAngle",Math::deg(innerAngle)));
	outerAngle=Math::rad(cfs.retrieveValue<Scalar>("./outerAngle",Math::deg(outerAngle)));
	drawMovementCircles=cfs.retrieveValue<bool>("./drawMovementCircles",drawMovementCircles);
	movementCircleColor=cfs.retrieveValue<Color>("./movementCircleColor",movementCircleColor);
	
	/* Set tool class' factory pointer: */
	WalkNavigationTool::factory=this;
	}
void SixAxisTransformTool::buttonCallback(int buttonSlotIndex,InputDevice::ButtonCallbackData* cbData)
	{
	if(buttonSlotIndex==0)
		{
		if(cbData->newButtonState) // Button has just been pressed
			{
			/* Reset the transformed device to the home position: */
			transformedDevice->setTransformation(TrackerState::translateFromOriginTo(config.followDisplayCenter?getDisplayCenter():config.homePosition));
			}
		}
	else
		{
		/* Let transform tool handle it: */
		TransformTool::buttonCallback(buttonSlotIndex,cbData);
		}
	}
void ViewpointFileNavigationTool::readViewpointFile(const char* fileName)
	{
	try
		{
		/* Open the viewpoint file: */
		Misc::File viewpointFile(fileName,"rt");
		
		if(Misc::hasCaseExtension(fileName,".views"))
			{
			/* Load all viewpoint keyframes from the file: */
			Scalar time(0);
			while(true)
				{
				/* Read the next viewpoint: */
				Scalar timeInterval;
				ControlPoint v;
				if(fscanf(viewpointFile.getFilePtr(),"%lf (%lf, %lf, %lf) %lf (%lf, %lf, %lf) (%lf, %lf, %lf)\n",&timeInterval,&v.center[0],&v.center[1],&v.center[2],&v.size,&v.forward[0],&v.forward[1],&v.forward[2],&v.up[0],&v.up[1],&v.up[2])!=11)
					break;
				
				/* Store the viewpoint: */
				time+=timeInterval;
				times.push_back(time);
				v.size=Math::log(v.size); // Sizes are interpolated logarithmically
				viewpoints.push_back(v);
				}
			
			if(viewpoints.size()>1)
				{
				/* Create a big matrix to solve the C^2 spline problem: */
				unsigned int n=viewpoints.size()-1;
				Math::Matrix A(4*n,4*n,0.0);
				Math::Matrix b(4*n,10,0.0);
				
				A(0,0)=1.0;
				writeControlPoint(viewpoints[0],b,0);
				
				double dt1=double(times[1])-double(times[0]);
				#if 1
				/* Zero velocity at start: */
				A(1,0)=-3.0/dt1;
				A(1,1)=3.0/dt1;
				#else
				/* Zero acceleration at start: */
				A(1,0)=6.0/Math::sqr(dt1);
				A(1,1)=-12.0/Math::sqr(dt1);
				A(1,2)=6.0/Math::sqr(dt1);
				#endif
				
				for(unsigned int i=1;i<n;++i)
					{
					double dt0=double(times[i])-double(times[i-1]);
					double dt1=double(times[i+1])-double(times[i]);
					A(i*4-2,i*4-3)=6.0/Math::sqr(dt0);
					A(i*4-2,i*4-2)=-12.0/Math::sqr(dt0);
					A(i*4-2,i*4-1)=6.0/Math::sqr(dt0);
					A(i*4-2,i*4+0)=-6.0/Math::sqr(dt1);
					A(i*4-2,i*4+1)=12.0/Math::sqr(dt1);
					A(i*4-2,i*4+2)=-6.0/Math::sqr(dt1);
					
					A(i*4-1,i*4-2)=-3.0/dt0;
					A(i*4-1,i*4-1)=3.0/dt0;
					A(i*4-1,i*4+0)=3/dt1;
					A(i*4-1,i*4+1)=-3/dt1;
					
					A(i*4+0,i*4-1)=1.0;
					writeControlPoint(viewpoints[i],b,i*4+0);
					
					A(i*4+1,i*4+0)=1.0;
					writeControlPoint(viewpoints[i],b,i*4+1);
					}
				
				double dtn=double(times[n])-double(times[n-1]);
				#if 1
				/* Zero velocity at end: */
				A(n*4-2,n*4-2)=-3.0/dtn;
				A(n*4-2,n*4-1)=3.0/dtn;
				#else
				/* Zero acceleration at end: */
				A(n*4-2,n*4-3)=6.0/Math::sqr(dtn);
				A(n*4-2,n*4-2)=-12.0/Math::sqr(dtn);
				A(n*4-2,n*4-1)=6.0/Math::sqr(dtn);
				#endif
				
				A(n*4-1,n*4-1)=1.0;
				writeControlPoint(viewpoints[n],b,n*4-1);
				
				/* Solve the system of equations: */
				Math::Matrix x=b/A;
				
				/* Create the spline segment list: */
				for(unsigned int i=0;i<n;++i)
					{
					SplineSegment s;
					for(int j=0;j<2;++j)
						s.t[j]=times[i+j];
					for(int cp=0;cp<4;++cp)
						{
						for(int j=0;j<3;++j)
							s.p[cp].center[j]=x(i*4+cp,j);
						s.p[cp].size=x(i*4+cp,3);
						for(int j=0;j<3;++j)
							s.p[cp].forward[j]=x(i*4+cp,4+j);
						for(int j=0;j<3;++j)
							s.p[cp].up[j]=x(i*4+cp,7+j);
						}
					splines.push_back(s);
					}
				}
			}
		else if(Misc::hasCaseExtension(fileName,".curve"))
			{
			/* Load all spline segments from the file: */
			while(true)
				{
				SplineSegment s;
				if(splines.empty())
					{
					/* Read the first control point: */
					ControlPoint cp;
					if(fscanf(viewpointFile.getFilePtr(),"(%lf, %lf, %lf) %lf (%lf, %lf, %lf) (%lf, %lf, %lf)\n",&cp.center[0],&cp.center[1],&cp.center[2],&cp.size,&cp.forward[0],&cp.forward[1],&cp.forward[2],&cp.up[0],&cp.up[1],&cp.up[2])!=10)
						break;
					cp.size=Math::log(cp.size); // Sizes are interpolated logarithmically
					viewpoints.push_back(cp);
					times.push_back(Scalar(0));
					s.t[0]=Scalar(0);
					s.p[0]=cp;
					}
				else
					{
					/* Copy the last control point from the previous segment: */
					s.t[0]=splines.back().t[1];
					s.p[0]=splines.back().p[3];
					}
				
				/* Read the segment's parameter interval: */
				double pi;
				if(fscanf(viewpointFile.getFilePtr(),"%lf\n",&pi)!=1)
					break;
				s.t[1]=s.t[0]+Scalar(pi);
				
				/* Read the intermediate control points: */
				ControlPoint m0;
				if(fscanf(viewpointFile.getFilePtr(),"(%lf, %lf, %lf) %lf (%lf, %lf, %lf) (%lf, %lf, %lf)\n",&m0.center[0],&m0.center[1],&m0.center[2],&m0.size,&m0.forward[0],&m0.forward[1],&m0.forward[2],&m0.up[0],&m0.up[1],&m0.up[2])!=10)
					break;
				m0.size=Math::log(m0.size); // Sizes are interpolated logarithmically
				s.p[1]=m0;
				ControlPoint m1;
				if(fscanf(viewpointFile.getFilePtr(),"(%lf, %lf, %lf) %lf (%lf, %lf, %lf) (%lf, %lf, %lf)\n",&m1.center[0],&m1.center[1],&m1.center[2],&m1.size,&m1.forward[0],&m1.forward[1],&m1.forward[2],&m1.up[0],&m1.up[1],&m1.up[2])!=10)
					break;
				m1.size=Math::log(m1.size); // Sizes are interpolated logarithmically
				s.p[2]=m1;
				
				/* Read the last control point: */
				ControlPoint cp;
				if(fscanf(viewpointFile.getFilePtr(),"(%lf, %lf, %lf) %lf (%lf, %lf, %lf) (%lf, %lf, %lf)\n",&cp.center[0],&cp.center[1],&cp.center[2],&cp.size,&cp.forward[0],&cp.forward[1],&cp.forward[2],&cp.up[0],&cp.up[1],&cp.up[2])!=10)
					break;
				cp.size=Math::log(cp.size); // Sizes are interpolated logarithmically
				viewpoints.push_back(cp);
				times.push_back(s.t[1]);
				s.p[3]=cp;
				
				/* Save the spline segment: */
				splines.push_back(s);
				}
			}
		else
			{
			/* Display an error message: */
			std::string message="Curve file ";
			message.append(fileName);
			message.append(" has unrecognized extension \"");
			message.append(Misc::getExtension(fileName));
			message.push_back('"');
			showErrorMessage("Curve File Animation",message.c_str());
			}
		}
	catch(std::runtime_error err)
		{
		/* Display an error message: */
		std::string message="Could not read curve file ";
		message.append(fileName);
		message.append(" due to exception ");
		message.append(err.what());
		showErrorMessage("Curve File Animation",message.c_str());
		}
	
	if(!splines.empty())
		{
		/* Start animating from the beginning: */
		paused=false;
		parameter=splines.front().t[0];
		
		/* Create playback control dialog if requested: */
		if(showGui)
			createGui();
		
		/* Start animating if requested: */
		if(autostart)
			activate();
		}
	else if(!viewpoints.empty()&&activate())
		{
		/* Go to the first viewpoint: */
		const ControlPoint& v=viewpoints[0];
		NavTransform nav=NavTransform::identity;
		nav*=NavTransform::translateFromOriginTo(getDisplayCenter());
		nav*=NavTransform::rotate(Rotation::fromBaseVectors(Geometry::cross(getForwardDirection(),getUpDirection()),getForwardDirection()));
		nav*=NavTransform::scale(getDisplaySize()/Math::exp(v.size)); // Scales are interpolated logarithmically
		nav*=NavTransform::rotate(Geometry::invert(Rotation::fromBaseVectors(Geometry::cross(v.forward,v.up),v.forward)));
		nav*=NavTransform::translateToOriginFrom(v.center);
		setNavigationTransformation(nav);
		
		deactivate();
		}
	}
Exemple #16
0
UIManagerSpherical::UIManagerSpherical(const Misc::ConfigurationFileSection& configFileSection)
	:UIManager(configFileSection),
	 sphere(Point::origin,Scalar(1)),
	 alignSecant(configFileSection.retrieveValue<bool>("./alignSecant",true)),
	 constrainMovement(configFileSection.retrieveValue<bool>("./constrainMovement",true))
	{
	/* Configure the UI sphere: */
	sphere.setCenter(configFileSection.retrieveValue<Point>("./sphereCenter"));
	sphere.setRadius(configFileSection.retrieveValue<Scalar>("./sphereRadius",Geometry::dist(sphere.getCenter(),getDisplayCenter())));
	}
void ComeHitherNavigationTool::buttonCallback(int,int,InputDevice::ButtonCallbackData* cbData)
	{
	if(cbData->newButtonState) // Button has just been pressed
		{
		if(isActive()) // Tool is already active
			{
			/* Snap to the target transformation immediately: */
			setNavigationTransformation(targetNav);
			
			/* Deactivate this tool: */
			deactivate();
			}
		else // Tool is not yet active
			{
			/* Try activating this tool: */
			if(activate())
				{
				/* Get the start navigation transformation: */
				startNav=getNavigationTransformation();
				startTime=getApplicationTime();
				
				/* Get the target transformation: */
				NavTransform device=getDeviceTransformation(0);
				device.leftMultiply(getInverseNavigationTransformation());
				Point center=device.getOrigin();
				Vector forward=device.getDirection(1);
				Vector up=device.getDirection(2);
				
				/* Compute the navigation transformation for the target transformation: */
				targetNav=NavTransform::identity;
				targetNav*=NavTransform::translateFromOriginTo(getDisplayCenter());
				targetNav*=NavTransform::rotate(Rotation::fromBaseVectors(Geometry::cross(getForwardDirection(),getUpDirection()),getForwardDirection()));
				targetNav*=NavTransform::scale(startNav.getScaling());
				targetNav*=NavTransform::rotate(Geometry::invert(Rotation::fromBaseVectors(Geometry::cross(forward,up),forward)));
				targetNav*=NavTransform::translateToOriginFrom(center);
				
				/* Compute the linear and angular velocities for the movement: */
				NavTransform delta=startNav;
				delta.doInvert();
				delta.leftMultiply(targetNav);
				Vector linearDist=delta.getTranslation();
				double linearMag=Geometry::mag(linearDist);
				Vector angularDist=delta.getRotation().getScaledAxis();
				double angularMag=Geometry::mag(angularDist);
				if(linearMag<=factory->linearSnapThreshold&&angularMag<=factory->angularSnapThreshold)
					{
					/* Snap to the target transformation immediately: */
					setNavigationTransformation(targetNav);
					
					/* Deactivate this tool: */
					deactivate();
					}
				else
					{
					/* Compute the total transition time: */
					double transitionTime=linearMag/factory->maxLinearVelocity;
					if(transitionTime<angularMag/factory->maxAngularVelocity)
						transitionTime=angularMag/factory->maxAngularVelocity;
					endTime=startTime+transitionTime;
					
					/* Compute the effective linear and angular velocities: */
					linearVelocity=linearDist/Scalar(transitionTime);
					angularVelocity=angularDist/Scalar(transitionTime);
					}
				}
			}
		}
	}
void SixAxisTransformTool::initialize(void)
	{
	/* Let the base class do its thing: */
	TransformTool::initialize();
	
	/* Calculate derived configuration values: */
	for(int i=0;i<3;++i)
		translations[i]=config.translations[i]*config.translateFactor;
	for(int i=0;i<3;++i)
		rotations[i]=config.rotations[i]*Math::rad(config.rotateFactor);
	
	/* Set the virtual input device's glyph: */
	getInputGraphManager()->getInputDeviceGlyph(transformedDevice).setGlyphType(config.deviceGlyphType.c_str());
	getInputGraphManager()->getInputDeviceGlyph(transformedDevice).setGlyphMaterial(config.deviceGlyphMaterial);
	
	/* Initialize the virtual input device's position: */
	transformedDevice->setDeviceRay(Vector(0,1,0),-getInchFactor());
	transformedDevice->setTransformation(TrackerState::translateFromOriginTo(config.followDisplayCenter?getDisplayCenter():config.homePosition));
	}