[JAVA3d] Problem with SpaceMouse Coordonote

Post questions, comments and feedback to our 3Dconnexion Windows Development Team.

Moderator: Moderators

Post Reply
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

[JAVA3d] Problem with SpaceMouse Coordonote

Post by lololem »

Hello, I developped a big application in Java3d that I make interact with SpaceMouse. For this interaction, I use the JNI who you have us precedetly supplies (viewtopic.php?t=691) but also there is many problems with the axes (The same problem like chamorrus). Now I have a big problem when I pass in mode FLY (observer), my camera takes place in fixed coordinates and I do not see where the coordonate from.

Can help me?
Thank you

loic

The code :

SpaceMouseBehavior

Code: Select all

package interaction;

import javax.media.j3d.WakeupCondition;
import javax.media.j3d.WakeupOnElapsedFrames;
import javax.media.j3d.Behavior;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.Transform3D;
import javax.media.j3d.Sensor;
import javax.vecmath.*;

/** Class to apply a Sensor's Transform3D to a TransformGroup
 *@author Designed by Boran Gögetap, Continental Software Design. Freeware.
 */
public class SpacemouseBehavior extends Behavior
{
	static Sensor sens;

	/** this holds the Group to Transform
	 */
	protected TransformGroup transformGroup;

	/** this holds the Sensor's latest data
	 */
	protected Transform3D currXform = new Transform3D();
		
	/** supply TransformGroup and Sensor in the constructor
	 */
	public SpacemouseBehavior( TransformGroup transformGroup, Sensor sens )
	{
		//System.out.println( "SpacemouseBehavior.SpacemouseBehavior()" );

		this.transformGroup = transformGroup;
                this.sens = sens;
	}
		
	/** used by j3d framework, not to be called by application
	 */
	public void initialize()
	{
		System.out.println( "initialisation..." );
		WakeupCondition wu = new WakeupOnElapsedFrames( 1 );		
		wakeupOn( wu );
	}
		
	/** used by j3d framework, not to be called by application
	 */
	public void processStimulus(java.util.Enumeration criteria)
        {
	       //Matrix3d matrice = new Matrix3d();
               //Vector3d vecteur = new Vector3d();
               
               sens.getRead( currXform );
               
               //currXform.get(matrice,vecteur);
               //System.out.println(matrice +"  "+vecteur); 
                              
	       transformGroup.setTransform( currXform );
      			
	       WakeupCondition wu = new WakeupOnElapsedFrames( 1 );
               
	       wakeupOn( wu );
                
	}
}
SpaceMouseDevice

Code: Select all

package device;
//package materiel.capteur3d;
//package device;

import javax.media.j3d.InputDevice;
import javax.media.j3d.Sensor;
import javax.media.j3d.Transform3D;
import javax.vecmath.*;



import java.io.*;

//import com._3Dconnexion.*;

/**
 * Class to support Space Control's Spacemouse (also known as Space Controller or Magellan)
 * 
 * changed to support the newer InputDevice interface found in Java 3D 1.2 final.
 * 
 * depends on MglStreams by Joerg Vogel (see author info in respective class)
 * 
 *@author Designed by Boran Gögetap, CONTINENTAL SOFTWARE Design. All rights reserved.
 */
public class SpacemouseDevice implements InputDevice
{
	/** holds translational data */
	protected static Vector3d	translation = new Vector3d();

	/** holds combined rotational data */
	protected static Matrix3d	rotation =	new Matrix3d();

	/** holds rotation about X axis */
	protected static Matrix3d	rX =		new Matrix3d();

	/** holds rotation about Y axis */
	protected static Matrix3d	rY =		new Matrix3d();

	/** holds rotation about Z axis */
 	protected static Matrix3d	rZ =		new Matrix3d();
	
	/** holds translational scale, default = 0.001 */
	protected static double Tscale = 0.0001;
	
	/** holds rotational scale, default = 0.001	 */
	protected static double Rscale = 0.0001;
	
	/** holds Sensor object which is managed by this device
	 */
	protected static Sensor	sens;
	
	/** access to 3DxWare driver
	 */
	protected static JNIsiapp siapp;
	private static boolean firstTime = true;

	private static char inbuffer[] = new char[1000];

	private static int stelle = 0;
	private static boolean indaten = false;
	
	/** taken from CDK's object model */
	protected static boolean accumflag = false;
	
	/** taken from CDK's object model */
	protected static boolean dirtyflag = true;
	
	//boolean	translock, rotlock, dominant;
	//int		fehlerpakete, iolength;

	/** raw data from Spacemouse */
	protected static int	MagellanData[] = new int[6];

	/** handle to inputstream, outputstream + helper funtions to communicate with Spacemouse */
	//protected MglStreams streams;
	
	/**
	 * get raw data.
	 * @return 6 integer values.
	 */
	public int[]	getMagellanData()
	{
		return MagellanData;
	}
	
	/** taken from Space Control's reference implementation */
	private StringBuffer MagellanNibbleList = new StringBuffer( "0AB3D56GH9:K<MN?" );

	
	/**
	 * nom de la frame
	 */
	private String nomFrame;

	
	/** taken from Space Control's reference implementation */
	private int MagellanNibbleMask( int Value )
	{
		return Value & 0x000F;
	}

	/** taken from Space Control's reference implementation */
	private boolean isNibble( char CHAR )
	{
		return MagellanNibbleList.charAt( CHAR&0x0F ) == CHAR;
	}
	
	/**
	 *  taken from CDK's object model, controls whether or not to accumulate data samples and effectively make Spacemouse an absolute sensor rather than a relative one.
	 */
	public void SetAccumFlag( boolean accumflag )
	{
		this.accumflag = accumflag;
	}
	
	/**
	 *  taken from CDK's object model, used to scale rotational data; 0.001 is a reasonable value and also the default
	 */
	public void SetRscale( double Rscale )
	{
		this.Rscale = Rscale;
	}


	/**
	 *  taken from CDK's object model, used to scale translational data; 0.001 is a reasonable value and also the default
	 */
	public void SetTscale( double Tscale )
	{
		this.Tscale = Tscale;
	}

	//
	//	Konstruktoren:
	//
	
	/** construct using default port
	 */
	public SpacemouseDevice()
	{
		setNomFrame("VRMiner");
	        System.out.println("java.home is " + System.getProperty("java.home"));	    

/*
		streams = new MglStreams();
		streams.open();
		streams.reset(); 
*/
		sens = new Sensor( this, 1 );
                
		rotation.setIdentity();
	}
	
	
	//
	//	Device Interface Implementierungen:
	//
	
	/** used by j3d framework, not to be called by application
	 */
	public void close()
	{
		System.out.println( "Closing device.." );

		//streams.close();
	}

	
	/** used by j3d framework, not to be called by application
	 */
	public boolean initialize()
	{
		System.out.println( "initializing device..." );
		
		for( int i=0; i < 0; ++i )
		{
			sens.setNextSensorRead(
				System.currentTimeMillis(),
				new Transform3D(
					new Matrix3d(),
					new Vector3d(10.0,10.0,10.0),
					1
				),
				new int[0]
			);
		}
                System.out.println( "initialized." );
		return true;
	}
	
	
	/** used by j3d framework, useless for application
	 */
	public int getProcessingMode()
	{
		return InputDevice.BLOCKING;
	}
	
	
	/** used by j3d framework, not to be called by application; always returns 1
	 */
	public int getSensorCount()
	{
		//System.out.println( "SpacemouseDevice.getSensorCount()" );
		return 1;
	}
	
	
	/** used by j3d framework, not to be called by application; always returns the one and only Sensor
	 */
	public Sensor getSensor(int sensorIndex)
	{
		//System.out.println( "SpacemouseDevice.getSensor(" + sensorIndex + ")" );
		return sens;
	}
	

	/** This method causes the device's sensor readings to be updated by the device driver. For BLOCKING and NON_BLOCKING drivers, this method is called regularly and the Java 3D implementation can cache the sensor values. For DEMAND_DRIVEN drivers this method is called each time one of the Sensor.getRead methods is called, and is not otherwise called.
	 */
	public void pollAndProcessInput()
	{
		try {
		    //    System.out.println("SpacemouseDevice: pollandprocessinput");
			if (firstTime) {
				firstTime = false;
				siapp = new JNIsiapp();
				siapp.SiInitialize();
				siapp.SiOpenWinInit(nomFrame,"eventCallback");
				//ouverture du flux
                                siapp.SiOpen();
                                System.out.println("Capteur 3D démarré.");
                        
			}

			// Go into a wait state waiting to be woken up by the JNIsiapp library
			siapp.SiWaitForEvent();

			// This isn't really necessary.  We don't return from SiWaitForEvent
			// unless a new event has arrived.
			if (siapp.SiIsNewDataAvail()) {
				siapp.SiGetEvent();
				System.out.println("Event type is "+siapp.event.type);
				
				// Motion event
				if (siapp.event.type == JNIsiapp.SiEventType.SI_MOTION_EVENT)
				{
				/*	
                                    System.out.println("Motion Event: "
									   +siapp.event.mData[0]+", "+
									   +siapp.event.mData[1]+", "+
									   +siapp.event.mData[2]+", "+
									   +siapp.event.mData[3]+", "+
									   +siapp.event.mData[4]+", "+
									   +siapp.event.mData[5]+", ");
                                    
                                        if(siapp.event.mData[0] < 0) System.out.println("Evenement 0 : Tire");     
                                        if(siapp.event.mData[1] < 0) System.out.println("Evenement 1 : Appui");  
                                        if(siapp.event.mData[2] < 0) System.out.println("Evenement 2 : droite");  
                                        if(siapp.event.mData[3] < 0) System.out.println("Evenement 3 : haut");  
                                        if(siapp.event.mData[4] < 0) System.out.println("Evenement 4 : Rotation");  
                                        if(siapp.event.mData[5] < 0) System.out.println("Evenement 5 : gauche");  
					*/
                                         
                                        ///////////////////////////
					//	Translation behandeln:
					///////////////////////////
					if( accumflag )
					{
						translation.add(
							new Vector3d(
								siapp.event.mData[JNIsiapp.SI_TX] * Tscale,
								siapp.event.mData[JNIsiapp.SI_TY] * Tscale,
							   -siapp.event.mData[JNIsiapp.SI_TZ] * Tscale
							)
						);
					}
					else
					{
						translation.set(
								siapp.event.mData[JNIsiapp.SI_TX] * Tscale,
								siapp.event.mData[JNIsiapp.SI_TY] * Tscale,
							   -siapp.event.mData[JNIsiapp.SI_TZ] * Tscale
						);
					}

					////////////////////////////////
					//	Rotation behandeln:
					////////////////////////////////
					rX.rotX( siapp.event.mData[JNIsiapp.SI_RX] * Rscale );
					rY.rotY( siapp.event.mData[JNIsiapp.SI_RY] * Rscale );
					rZ.rotZ(-siapp.event.mData[JNIsiapp.SI_RZ] * Rscale );

					if( !accumflag )
						rotation.setIdentity();
					
					/*	diese Reihenfolge erzeugt eine Matrix,
						welche zu CDK's Make6DRecord äquivalent ist:
					*/
					rotation.mul( rY, rotation );
					rotation.mul( rZ, rotation );
					rotation.mul( rX, rotation );
					
					sens.setNextSensorRead(
						System.currentTimeMillis(),
						new Transform3D(
							rotation,
							translation,
							1
						),
						new int[0]
					);
				}
				
				// Button event
				else if (siapp.event.type == JNIsiapp.SiEventType.SI_BUTTON_EVENT)
				{
					System.out.println("Button Event: ");
					System.out.println("	   last: "+siapp.event.bData.last);
					System.out.println("	current: "+siapp.event.bData.current);
					System.out.println("	pressed: "+siapp.event.bData.pressed);
					System.out.println("   released: "+siapp.event.bData.released);
                                        //reset!
                                        translation.set(0,0,0);
                                                                          
                                        rotation.setIdentity();
                                        rotation.mul(rX);
                                        rotation.mul(rY);
                                        rotation.mul(rZ);
           
                                        accumflag = false;
				}

				// Button event
				else if (siapp.event.type == JNIsiapp.SiEventType.SI_ZERO_EVENT)
				{
					System.out.println("Attente d'une action");
				}
			}	
		} catch (Exception e) {
			System.out.println("Exception in JNIsiappThread: "+e);
			siapp.SiClose();
			siapp.SiTerminate();
		}
	}
	
	/** This method will not be called by the Java 3D implementation and should be implemented as an empty method.
	 */
	public void processStreamInput()
	{
	}

	/** used by j3d framework, not to be called by application - NOT IMPLEMENTED
	 */
	public void setNominalPositionAndOrientation()
	{
		System.out.println( "SpacemouseDevice.setNominalPositionAndOrientation()" );
	}
	
	/** used by j3d framework, not to be called by application - NOT IMPLEMENTED
	 */
	public void setProcessingMode(int mode)
	{
		System.out.println( "SpacemouseDevice.setProcessingMode(" + mode + ")" );
	}

	/**
	 * obtient le nom de la frame
	 * @return le nom de la frame
	 */
	public String getNomFrame() {
		return nomFrame;
	}
	/**
	 * definit le nom de la frame
	 * @param nomFrame le nom de la frame
	 */
	public void setNomFrame(String nomFrame) {
		this.nomFrame = nomFrame;
	}
}
jwick
Moderator
Moderator
Posts: 3341
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

Hi lololem,

( Finally a math question!!! :D )

You need to assume that the data from the 3Dx device is coming from the user. Therefore it is in "eye space".

To apply the transforms to the eye is simple--just move the camera position in camera space.

To apply the transforms to another object, say something in the scene, you need to transform the data vectors (translation and rotation vectors from the device) to the object's coordinate space before applying the changes.

This typically involves transforming the two vectors, backwards through the camera orientation to the world space, then possibly backwards through the objectToWorld transformation matrix to the objects coordinate system. The orientation is the only thing that matters.

The translation and rotation vectors must be reoriented so they faithfully indicate the correct direction the user was pushing (in eye space), but in the target coordinate system.

From your description, it sounds like you are moving your objects correctly, but moving your camera in the object's coordinate system, instead of the the camera's coordinate system.

You need to get a handle on exactly what coordinate system is in use for each object/camera/space... then apply the data in that coordinate system (transformed as necessary).

Jim
3Dx Software Development
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

I find that in spaceMouseDevice

setNominalPositionAndOrientation()

But this function is not implemented.

I want just choice the first point of my camera.
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

Hi jwick thank u for u rapidely answer.

I not move the object, i move the camera but the problem is the eyes is behind the cube (I can see nothing). I have to rotate for see the cube and after i can move in FlyMod in my cube and see my object in my cube.
The flymod runs its just the coordonate of begining is false.
I try to influate in the vector and rotator's matrix but nothing. When i choose the FlyMode, directely the SpaceMouse forget the coordonate of camera and go to the origin coordonate.

In my application i create five mode :


- Keybord (For Zoom - Translate)
- Mouse (Rotate)
- Examine (if Only the object)
- SpaceMouseFly (The mode of my problem)
- SpaceMouseExamine (This mode function)

Sorry i am french, can u explain with simple word and schematic ;) Thanks
jwick
Moderator
Moderator
Posts: 3341
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

Hi lololem,

Please don't assume that the mathematics in the JNI demo are fully correct. It is only meant to show how to get the data. I have no idea where the original code came from or what it was used for.

It sounds like your camera may be facing the wrong direction when you switch into FlyMod. Perhaps your camera direction vector needs to be flipped? Or you can move the camera position to the other side of the cube to start with. IOW, if it is at (0,0,10), maybe you should start at (0,0,-10). It all depends on the coordinate systems that you set up and where you place your objects and your cameras in your coordinate systems.

When I have problems like this, I print out a lot of data: the position and orientation of my object (the cube), the position and orientation of the camera, etc. I see if these values make sense and look at how these values change to see if they are changing in the correct direction.

Jim
3Dx Software Development
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

Thanks Jim for your advice.

I try and i will contact you for say u where the problem from

Byebye
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

Hi jim,

I don't find, i have always the same problem.

I think the origin of problem from my construct of BranchView but i don't know where is my error. May u can see it....

I try to modifie my coordonate with viewXfm.set(new Vector3f(0.0f, 0.0f, -10.0f)); but no success.

Code: Select all

protected BranchGroup buildViewBranch(Canvas3D c)
    {
        
        BranchGroup viewBranch = new BranchGroup();
        Transform3D viewXfm = new Transform3D();
        
        viewXfm.set(new Vector3f(0.0f, 0.0f, -10.0f));
        TransformGroup viewXfmGroup = new TransformGroup(viewXfm);
        
        viewXfmGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
        viewXfmGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        
        BoundingSphere movingBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
        BoundingLeaf boundLeaf = new BoundingLeaf(movingBounds);
        
        ViewPlatform myViewPlatform = new ViewPlatform();
       
        
        viewXfmGroup.addChild(boundLeaf);
        PhysicalBody myBody = new PhysicalBody();
               
        myEnvironment = new PhysicalEnvironment();
        //myEnvironment.addInputDevice(dev.getDevice());
        viewXfmGroup.addChild(myViewPlatform);
        viewBranch.addChild(viewXfmGroup);
      
    
        View myView = new View();
        myView.addCanvas3D(c);
        myView.setBackClipDistance(100000);
        myView.attachViewPlatform(myViewPlatform);
        myView.setPhysicalBody(myBody);
        myView.setPhysicalEnvironment(myEnvironment);
        
Thanks a lot
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

An other thing.

I construct my universe like that :

Code: Select all

 panel3D = pan;
        //Création du Canvas 3D
        c = createCanvas3D();
        
        //Ajout du mouseListener pour le menu contextuel
        MouseListener ml = new EcouteurPourPopup();
        getCanvas().addMouseListener(ml);
        
        //Creation de l'univers virtuel
        m_Universe = new VirtualUniverse();
        
        //Creation d'un local
        locale = new Locale(m_Universe);
        
        //Création d'un BranchGroup Principal ainsi que du TG de la scène
        root = new BranchGroup();
        root.setCapability(Group.ALLOW_CHILDREN_EXTEND);
        root.setCapability(BranchGroup.ALLOW_DETACH);
        root.setCapability(Group.ALLOW_CHILDREN_READ);
        root.setCapability(Group.ALLOW_CHILDREN_WRITE);
             
        sceneTransform = new TransformGroup();
        //Configuration des autorisation pour le TG
        sceneTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
        sceneTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        sceneTransform.setCapability(BranchGroup.ALLOW_DETACH);
        sceneTransform.setCapability(Group.ALLOW_CHILDREN_EXTEND);
        //ajout du TG au BG principal
        root.addChild(sceneTransform);
        
        //Création d'un BranchGroup pour la scène
        //Configuration des autorisations
        BranchGroup sceneBranchGroup = createSceneBranchGroup();
        //sceneBranchGroup.setUserData("root");
        //bgHashtable.put("root",sceneBranchGroup);
        sceneBranchGroup.setCapability(Group.ALLOW_CHILDREN_EXTEND);
        sceneBranchGroup.setCapability(BranchGroup.ALLOW_DETACH);
        sceneBranchGroup.setCapability(Group.ALLOW_CHILDREN_READ);
        sceneBranchGroup.setCapability(Group.ALLOW_CHILDREN_WRITE);
        
        //Ajout du branchgroup au transformGroup principal de la scène (pour le mode 'examine')
        sceneTransform.addChild(sceneBranchGroup);
        
       

      //Here i create my ViewBranch
       BranchGroup bgViewBranch = buildViewBranch(getCanvas());
       



        //Ajout de la branche de vue au Locale
        locale.addBranchGraph(bgViewBranch);
        
        //Récupération de la plateforme de vue(transformGroup)
        vpTrans = (TransformGroup)bgViewBranch.getChild(0);
              
        //création des comportements
        createBehavior();
         
        //Création du branchGroup pour l'objet showCoordinate 
        showCoordinate = new BranchGroup();
        showCoordinate.setCapability(BranchGroup.ALLOW_DETACH);
        
        //Ajoute le popupMenu système.
        popupMenu = new systemPopupMenu(panel3D,"Main menu",this);
        popupMenu.addClassicItems();
       
and when i have initialise my transform group vptrans, i use like that :

Code: Select all

spacemouseBehaviorFly = new SpacemouseBehavior(vpTrans, capteur);
    spacemouseBehaviorFly.setSchedulingBounds(bounds);
    BGBehaviorSpaceMouseFly.addChild(spacemouseBehaviorFly); 
Thanks a lot
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

Anybody ?
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

:(
jwick
Moderator
Moderator
Posts: 3341
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

I'm sorry lololem, I can't debug your code. I'd need all of it just to understand everything you are doing. You are going to have to understand the math that you have written. My post above states what needs to be done. It is a slow process, but you will have fun solving the problem. You really don't understand code like this until you know exactly what each line is doing. It is the nature of 3D math. Dig in and solve it!!!
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

oki it's done,

Thanks jim, i can now positionnate my camera where i want.

Merry Christmas

++
jwick
Moderator
Moderator
Posts: 3341
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

What did you have to do?
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

Just influate on the field Translation in SpaceMouseDevice

For exemple translation.set(10,10,10);
Post Reply