capÍtulo 16

42
1 VRML 2.0 con Java CAPÍTULO 16 Métodos y narrativas de Dispositivos de Apoyo

Upload: hinago

Post on 12-Jun-2015

97 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: CAPÍTULO  16

1

VRML 2.0 con Java CAPÍTULO 16

Métodos y narrativas de Dispositivos de Apoyo

Page 2: CAPÍTULO  16

2

VRML 2.0 con Java CAPÍTULO 16

Contenido CAPÍTULO 16          • La clase Input6D      • Los métodos nativos      • Definición de los prototipos      • El código de Java para el Nodo de secuencias de comandos      • cuaterniones      • Un archivo de ejemplo      • Problemas de rendimiento y disponibilidad      • Orientación futura 

Page 3: CAPÍTULO  16

3

VRML 2.0 con Java CAPÍTULO 16

La clase Input6D 

Input6D la clase será lo suficientemente generales como para apoyar una amplia gama de dispositivos de entrada. Asimismo, ser independiente del dispositivo y de plataforma independiente, puesto que todas las dependencias serán manejadas por el nativo de los métodos de la clase. Haremos la mayor parte del procesamiento de los datos de sensor en Java, con el fin de reducir la cantidad de trabajo que tiene que hacerse en los nativos y, por ende, los métodos que sean más fáciles de aplicar. 

Dado que puede haber múltiples dispositivos de entrada en una sola máquina, necesitamos alguna forma de identificar dispositivos específicos sin hacer ninguna hipótesis acerca de ellos. Lo haremos por la asociación de un número de puerto con cada uno de ellos. El número de puerto será un entero simple, que puede ser vinculado a un dispositivo real de la utilización de algunos mecanismos específicos de plataforma. Esto permite a los constructores-avatar simplemente decir: "Jefe de seguimiento en el puerto es 0, el seguimiento de la mano izquierda está en el puerto 1, y el seguimiento de la mano derecha en el puerto 2," sin preocuparse de que los dispositivos que el usuario pasa a tener instalado . El puerto será una variable de instancia de la clase Input6D, ya que cada objeto de esa clase tendrá su propio puerto. 

La clase Input6D tendrá también variables de instancia para el almacenamiento de leer el último conjunto de valores de datos en bruto. Las traducciones se almacenan en las variables rawX, rawY, y rawZ, y las rotaciones se rawR, rawU, y rawV. También habrá un 32-bit de los pabellones de los diferentes botones en el dispositivo, así como una variable que los registros que el botón se presiona más recientemente. Por último, tendremos un entero para almacenar el estado de la operación más reciente en el dispositivo y un par de operaciones booleanas para indicar si el dispositivo se ha desplazado desde la última encuesta, y si el estado de sus botones ha cambiado: 

/ / Clase para el manejo de 6 grados de libertad dispositivos 

/ / Escrito por Bernie Roehl, febrero de 1997 

clase pública Input6D (    protegidas int puerto; / / establecido por el constructor 

   / / Leer encuesta (): 

Page 4: CAPÍTULO  16

4

VRML 2.0 con Java CAPÍTULO 16

   flotador rawX protegidas, rawY, rawZ;    flotador rawR protegidas, rawU, rawV;    int botones protegidas;    int whichButton protegidas;    int estado protegidas;    protegidas boolean cambiado;    boolean buttonChanged protegidas; 

Los valores de obtener materias primas a escala, que se compensan, y, en general, procesados de diferentes maneras a fin de llegar a las lecturas de la realidad que se informó a la aplicación. Vamos a almacenar estos valores transformados como variables de instancia: 

/ / Valores transformados: protegidas flotar x, y, z; protegidas flotar r, u, v; 

Cada dispositivo tendrá una serie de información básica sobre sí mismo, algunos de los cuales vamos a utilizar en Input6D y algunos de los cuales vamos a ofrecer simplemente a la aplicación. Esta información consta de una descripción legible por humanos del dispositivo, un recuento del número de botones en el dispositivo, el rango de los límites de cada uno de los seis DOF, y el punto central para cada DOF. También vamos a mantener en torno a una bandera para mostrar que el dispositivo ha sido correctamente inicializado: 

/ / Conjunto de configuración (): Cadena descripción protegidas; / / nombre y la descripción int nbuttons protegidas; / / número de botones minX protegidas flotador, maxX, minY, maxY, minZ, maxZ; flotador minR protegidas, maxR, minu, maxU, minV, maxV; flotador centerX protegidas, centerY, centerZ; flotador centerR protegidas, centerU, centerV; boolean allsWell protegidas; 

La solicitud podrá así quieren los datos de la escala, por lo que proporcionar un factor de escala para cada DOF. Estos a 1.0 por defecto, pero pueden ser fácilmente modificados por la aplicación según sea necesario. 

Page 5: CAPÍTULO  16

5

VRML 2.0 con Java CAPÍTULO 16

/ / Conjunto de la demanda: protegidas flotar XScale = 1 septies, yScale = 1 septies, zScale = 1F; protegidas rScale flotador = 1 septies, uScale = 1 septies, vScale = 1F; 

Como se ha explicado anteriormente, un dispositivo de entrada puede proporcionar un control directo sobre los seis grados de libertad o control de la tasa de cambio de los valores. Vamos a mantener dos banderas, una para la traducción y para una rotación, que indique si el dispositivo de control o el valor de la tasa de cambio. Dado que el tipo de cambio se basará en el tiempo transcurrido entre lecturas consecutivas del dispositivo, también tendremos que hacer un seguimiento de si el dispositivo de la última encuesta: 

protegidas accumulateTranslations boolean = false; protegidas accumulateRotations boolean = false; largo lastPolled protegidas; 

Eso es todo para la variables de instancia. Hay una serie de métodos de acceso: 

flotador público getX () (return x;) flotador público Gety () (return y;) flotador público Getz () (return z;) flotador público getR () (return r;) flotador público getU () (return u;) flotador público getV () (return v;) público int getButton () (return whichButton;) público int getButtons () (return botones;) público int getStatus () (return estado;) público hasChanged boolean () (return cambiado;) público buttonHasChanged boolean () (return buttonChanged;) 

public void setX (float valor) (x = valor;) public void setY (float valor) (valor = y;) public void setZ (float valor) (z = valor;) public void setR (float valor) (r = valor;) public void Setu (float valor) (u = valor;) public void setV (float valor) (v = valor;) 

getDescription public String () (return descripción;) público int getNumberOfButtons () (return nbuttons;) público int getPort () (return puerto;) public void setPort (int p) (puerto = p;) flotador público getScaleX () (return XScale;) 

Page 6: CAPÍTULO  16

6

VRML 2.0 con Java CAPÍTULO 16

flotador público getScaleY () (return yScale;) flotador público getScaleZ () (return zScale;) public void setScaleX (float x) (XScale = x;) public void setScaleY (float y) (yScale = y;) public void setScaleZ (float z) (z = zScale;) 

flotador público getScaleR () (return rScale;) flotador público getScaleU () (return uScale;) flotador público getScaleV () (return vScale;) public void setScaleR (float r) (rScale = r;) public void setScaleU (float u) = u uScale (;) public void setScaleV (float v) (vScale = v;) 

público getAccumulateTranslations boolean () (    accumulateTranslations retorno; ) 

público getAccumulateRotations boolean () (    accumulateRotations retorno; ) 

public void setAccumulateTranslations (boolean valor) (    accumulateTranslations = valor; ) 

public void setAccumulateRotations (boolean valor) (    accumulateRotations = valor; ) 

Tenga en cuenta que el setX (), setY (), y otras funciones sólo son pertinentes si se acumulan las pabellón esté definido. Por ejemplo, si la solicitud se quiere restablecer las rotaciones a cero, puede utilizar el setR (), Setu (), y setV () los métodos para hacerlo. Si el dispositivo no está en el modo de acumular rotaciones, estos métodos tienen poco efecto, porque la próxima vez que lea el dispositivo de un nuevo conjunto de valores se definirán. 

Habrá dos métodos nativos. Uno de ellos creó el dispositivo, al restaurar si es necesario, y el otro dispositivo de la encuesta para los nuevos valores. Estas serán examinadas en detalle más adelante en este capítulo. Por ahora, basta con observar que tienen los nativos de palabras clave en frente de ellos para indicar que su aplicación es en realidad escrito en C o algún otro idioma. El nativeSetup () método es llamado sólo desde Input6D.setup (), que es generalmente llamado sólo desde el constructor: 

Page 7: CAPÍTULO  16

7

VRML 2.0 con Java CAPÍTULO 16

privado nativo vacío nativeSetup (); privado nativo vacío nativePoll (); 

público Input6D (int prt) (    port = prt;    configuración (); ) 

La configuración () llamadas a los métodos nativeSetup (), comprueba el estado de resultado, y establece la designación para el dispositivo de entrada para ser un mensaje de error si existe algún problema. Si todo está bien, el programa de instalación () entonces el dispositivo de las encuestas y utiliza los valores iniciales en bruto como el centro puntos. Tenga en cuenta que esto supone que el dispositivo está en su "descanso" o "cero" posición en el tiempo de inicio: 

public void setup () (    allsWell = true;    nativeSetup ();    if (estado! = 0) (       descripción = "No se pudo inicializar; código de error" estado;       allsWell = false;      )      / / Leer los valores iniciales, como el uso CenterPoint      = buttonChanged cambiado = false;      nativePoll ();      lastPolled = System.currentTimeMillis ();      centerX = rawX; centerY = rawY; centerZ = rawZ;      centerR = rawR; centerU = rawU; centerV = rawV;      maxX -= centerX; maxY -= centerY; maxZ -= centerZ;      maxR -= centerR; maxU -= centerU; maxV -= centerV;      minX -= centerX; minY -= centerY; minZ -= centerZ;      minR -= centerR; minu -= centerU; minV -= centerV;      if (maxX == 0) maxX = 1, si (minX == 0) minX = -1;      if (maxY == 0) maxY = 1, si (minY == 0) minY = -1;      if (maxZ == 0) maxZ = 1, si (minZ == 0) minZ = -1;      if (maxR == 0) maxR = 1, si (minR == 0) minR = -1;      if (maxU == 0) maxU = 1, si (minu == 0) minu = -1;      if (maxV == 0) maxV = 1, si (minV == 0) minV = -1; ) 

Los valores mínimos y máximos son fijados por el nativeSetup () el método, y nosotros inmediatamente compensado por el valor del punto central para cada DOF. Dado que será el punto central de restar los valores de cada muestra, tal como lo ha leído, estamos seguros de que 

Page 8: CAPÍTULO  16

8

VRML 2.0 con Java CAPÍTULO 16

efectivamente toma la posición de centrado en el canal es cero, y sus valores mínimo y máximo se ajustará en consecuencia. 

Dado que algunos dispositivos pueden apoyar menos de seis grados de libertad, y los valores mínimo y máximo para los canales sin aplicarse puede ser cero, se añade un control y establecer los valores en consecuencia.

El dispositivo de votación se realiza llamando a la encuesta () método. Se realiza un seguimiento de la última vez que el dispositivo fue encuestados, con el fin de la escala de valores de entrada cuando el accumulateTranslations o accumulateRotations banderas se establecen: 

public void encuesta () (    / / Actualizar el lastPolled tiempo    ahora System.currentTimeMillis largo = ();    = largo deltaT ahora - lastPolled;    = lastPolled ahora;    if (allsWell == false) (/ / no inicializadas       status = -1;       retorno;    )    / / Encuesta el dispositivo    = buttonChanged cambiado = false;    nativePoll ();    if (! cambiado)       retorno; 

El nativePoll () método es llamado, que se actualizarán los valores a lo largo de la materia prima con el botón y whichButton campos. Si el cambio de bandera no ha sido establecida, entonces el crudo valores son los mismos que fueron la última vez nativePoll () se ha llamado, por lo que no hay necesidad de procesar de nuevo. 

El siguiente paso es cambiar el valor bruto de modo que el punto central es cero, entonces por la escala de factores de escala y dividir por el rango. Si el valor bruto es negativo, el intervalo mínimo es utilizado como el divisor, de lo contrario, el alcance máximo se utiliza: 

/ / Cambio de centro rawX -= centerX; rawY -= centerY; rawZ -= centerZ; 

Page 9: CAPÍTULO  16

9

VRML 2.0 con Java CAPÍTULO 16

rawR -= centerR; rawU -= centerU; rawV -= centerV; / / Escala y en condiciones de gama flotador dx = rawX XScale * / ((rawX <0)?-minX: maxX); dy = yScale flotar rawY * / ((rawY <0)?-minY: maxY); flotador dz = zScale * rawZ / ((rawZ <0)?-minZ: maxZ); dr = rScale flotar rawR * / ((rawR <0)?-minR: maxR); del flotador = uScale * rawU / ((rawU <0)? minu-: maxU); dv = vScale flotar rawV * / ((rawV <0)?-minV: maxV); 

El paso final es comprobar si los valores están siendo "acumulado", es decir, comprobar si el dispositivo de control de los valores directamente o controle su tasa de cambio. Si es esto último, los valores que se computan sólo se escalan por el tiempo transcurrido (convertidos a segundos de dividir entre 1000) y se añaden a los valores actuales de las distintas variables. Si es la primera, los nuevos valores adquiridos se almacenan directamente en las variables de instancia: 

         / / Acumular          if (accumulateTranslations) (              dx = x + * deltaT / 1000;              y + = dy * deltaT / 1000;              + z = dz * deltaT / 1000;          )          else (              x = dx;              y = dy;              z = dz;          )          if (accumulateRotations) (              r + = dr * deltaT / 1000;              u + = du * deltaT / 1000;              v + = * deltaT dv / 1000;          )          else (              r = dr;              u = du;              v = dv;          )      ) 

Page 10: CAPÍTULO  16

10

VRML 2.0 con Java CAPÍTULO 16

     (System.loadLibrary estática ( "Input6D");) ) 

Observe que tenemos un inicializador estático que se carga la biblioteca Input6D, que en Windows 95 se llamará Input6D.DLL. Biblioteca que contendrá el código que implementa los métodos nativos. El Nativo de Métodos 

Input6D.DLL El archivo contiene los dos métodos nativos que se discutieron anteriormente. Esto sirve para aislarlos bien del resto del código que habrá una biblioteca dinámica Input6D en cada plataforma, y un usuario puede agregar el soporte para dispositivos inusual por proporcionar una Input6D que aplicar a sí mismos. 

Nuestra aplicación será diseñado para Windows 95, ya que es, de lejos, la plataforma más popular. Vamos a estar usando DirectInput, que es esencialmente un conjunto mejorado de mando de las rutinas en Windows 95 que admita dispositivos con hasta seis grados de libertad y múltiples botones. Vamos a guardar nuestro métodos nativos en un archivo llamado I6DImp.c, que serán compilados y vinculados, como se muestra más adelante en este capítulo. 

Los detalles de la aplicación, por supuesto, varían de una plataforma a otra. Esta es una razón por la cantidad de trabajo realizado en los métodos nativos se mantiene al mínimo, ya que el código debe volver a aplicarse en cada plataforma. El nativeSetup () Método 

El nativeSetup () método es muy sencillo: 

# include "Input6D.h" # include <windows.h> # include <string.h> 

vacío Input6D_nativeSetup (struct HInput6D * obj) (    ClassInput6D * = datos unhand (obj);    JOYCAPS gorras;    datos-> status = joyGetDevCaps (datos-> puerto, y gorras, sizeof (gorras));    if (datos-> estado! = 0) 

Page 11: CAPÍTULO  16

11

VRML 2.0 con Java CAPÍTULO 16

      retorno;    datos-> minX = caps.wXmin; datos> maxX = caps.wXmax;    de datos> = minY caps.wYmin; de datos> = maxY caps.wYmax;    datos-> minZ = caps.wXmin; de datos> maxZ = caps.wZmax;    datos-> minR = caps.wRmin; de datos> maxR = caps.wRmax;    de datos> = minu caps.wUmin; de datos> maxU = caps.wUmax;    datos-> minV = caps.wVmin; de datos> maxV = caps.wVmax;    datos-> nbuttons = caps.wNumButtons;    de datos> = makeJavaString descripción (           caps.szPname, strlen (caps.szPname)); ) 

Cuando se llama a este nativo de Java método, que pasa el mango del objeto Input6D como parámetro. El unhand () macro gira el mango en un puntero de tipo C, de manera que pueda ser utilizado para acceder a variables de instancia del objeto. Que macro, y una serie de aspecto algo extraño tipos de datos, son todos Input6D.h definidas en el archivo que se genera automáticamente para usted por javah. 

Un Windows 95 JOYCAPS se define la estructura, que se completará con las capacidades del dispositivo, seleccione joystick. Observe que el número de puerto que la solicitud se especifica en el constructor para el objeto Input6D se pasa directamente a la joyGetDevCaps () de rutina. Si el valor de retorno de rutina que es distinto de cero, sino que está almacenado en el campo de estado de la Input6D objeto. 

Si todo va bien, los valores mínimo y máximo se copian desde la estructura que fue rellenado por el joystick conductor. El número de botones es también más copiados, como es el nombre del conductor (con la makeJavaString () de rutina).

El nativePoll () Método 

El nativePoll () el método es muy similar a nativeSetup () y es casi tan sencilla: 

vacío Input6D_nativePoll (struct HInput6D * este) (    ClassInput6D * = datos unhand (este);    JOYINFOEX información;    info.dwSize = sizeof (info);    info.dwFlags = JOY_RETURNALL;    datos-> status = joyGetPosEx (datos-> puerto, & info); 

Page 12: CAPÍTULO  16

12

VRML 2.0 con Java CAPÍTULO 16

   datos-> rawX = info.dwXpos;    datos-> rawY = info.dwYpos;    datos-> rawZ = info.dwZpos;    datos-> rawR = info.dwRpos;    datos-> rawU = info.dwUpos;    datos-> rawV = info.dwVpos;    de datos> = 1 ha cambiado; / / true    if (datos-> botones! = info.dwButtons) (        de datos> = info.dwButtons botones;        datos-> whichButton = info.dwButtonNumber;        datos-> buttonChanged = 1; / / true    ) ) 

Un JOYINFOEX struct es creada, que mantendrá los datos del dispositivo DirectInput. Es necesario decirle a Windows el tamaño de la estructura de datos en el primer campo de la estructura y establecer un conjunto de banderas en el segundo campo para que el conductor sabe que los datos que deben regresar desde el dispositivo. En este caso, queremos que todos los datos que tiene. 

El valor de retorno de joyGetPosEx () es usado como el estado del dispositivo. Todos los valores se copian más, y el cambio de bandera se establece. Una aplicación más inteligente que comprobar si alguno de los valores de los datos han cambiado, y sólo establece el cambio de pabellón en caso necesario, lo que podría mejorar el desempeño en general, puesto que la aplicación tendría que hacer menos trabajo, si sabían que no habían llegado los nuevos datos. 

Por último, los botones están en comparación a su valor anterior para ver si alguno de ellos han cambiado. Si los botones han cambiado, los nuevos valores se leen, y el pabellón buttonChanged el valor true, que en este caso es 1, ya están representados por Booleanos C largo tipos de datos en un método nativo. El apoyo a múltiples tipos de dispositivos 

A primera vista, puede parecer que nos limitamos a nosotros mismos a un solo tipo de controlador de dispositivo, en este caso DirectInput. Que en realidad no es el caso. 

Si un usuario tiene alguna inusual dispositivo para el que ha escrito un controlador, que puede modificar I6DImp.c a fin de que las llamadas de su propio código para algunos números de puerto y DirectInput para otros. Obviamente, esto debe ser manejado tanto en el nativeSetup () y nativePoll () métodos. 

Por ejemplo, nativePoll () puede ser escrito como sigue: 

Page 13: CAPÍTULO  16

13

VRML 2.0 con Java CAPÍTULO 16

vacío Input6D_nativePoll (struct HInput6D * este) (    ClassInput6D * = datos unhand (este);    switch (datos-> puerto) (      case 0:      caso 1:      el caso 2:        readDirectInput (datos-> puerto, datos);        break;      caso 3:        readHeadTrackerDevice (datos-> puerto - 3, de datos);        break;      case 4:      caso 5:        readMyFunkyDevice (datos-> puerto - 4, datos);        break;      por defecto:        datos-> status = -1;        break;      ) ) 

En este caso, el readDirectInput () de rutina podría ser el mando de la lectura de código que le hemos analizado anteriormente; readHeadTrackerDevice () sería una rutina de leer el seguimiento de algunos cascos de visualización, y readMyFunkyDevice () sería una rutina de leer algún otro dispositivo de entrada que no es apoyada por DirectInput. Compilación de los métodos nativos 

Hay una serie de pasos involucrados en la compilación de los métodos nativos para su uso con Java. También hay un número específico de la plataforma y compilador de cuestiones específicas que deben tratarse. 

Si bien no es posible identificar todos los problemas en todas las diferentes plataformas, es interesante el paso a través del proceso de, al menos, una plataforma para ver lo que algunos de los escollos son. En este caso, vamos a estar usando Watcom C al compilar nuestro código nativo. 

La versión de Windows 95 JDK 1.0.2 está diseñado para trabajar con Microsoft Visual C + + versión 2.0 o posterior. Las versiones anteriores del compilador de Microsoft no son compatibles directamente, ni otros tales como compiladores Watcom. Esto lleva a algunos problemas, pero afortunadamente hay soluciones para todos ellos. Primer paso: Compilar el código de Java 

Page 14: CAPÍTULO  16

14

VRML 2.0 con Java CAPÍTULO 16

Comenzamos por compilar Input6D.java nuestro archivo: 

javac Input6D.java 

Esto, por supuesto, produce una Input6D.class archivo. Luego de que el proceso utilizando el archivo de clase javah utilidad. Lo hacemos dos veces, una para generar un archivo Input6D.h, y una vez para generar Input6D.c (un "tonto" archivo que contiene la capa rutinas que llamar a nuestra aplicación de métodos de los nativos): 

javah Input6D javah-talones Input6D 

Segundo paso: Compilar el código C 

Siguiente tenemos que compilar el archivo Input6D.c que acaba de crear, así como el archivo que contiene I6DImp.c nuestros métodos nativos. Usando Watcom C 10,6 o superior, debería ser sencillo, de empezar por asegurarse de que el archivo de cabecera de Java son los directorios mencionados en la variable de entorno INCLUYE: 

=% serie INCLUYE INCLUYE%; \ java \ include; \ java \ include \ win32 

Luego compilar el código usando la opción "-bd" Watcom opción que indica que estamos creando un archivo DLL: 

wcc386-bd Input6D.c 

Es en este punto que se empieza a ejecutar en problemas. Lo primero que observamos es que uno de los archivos de cabecera se suministra con el JDK, typedef_md.h, no compila porque utiliza un tipo de datos que no es estándar C. Que tipo de datos es Int64, uno de 64-bit que está disponible sólo en las últimas versiones de Microsoft C + +. Que puedan existir en cualquier compilador que se está usando y, de ser así, puede tener un nombre diferente. Si tu compilador tiene una de 64-bit tipo de datos, pero no lo llaman Int64, tendrá que modificar el archivo typedefs_md.h en consecuencia. 

En el caso de Watcom C, no es de 64-bit tipo de datos. Eso significa que no será capaz de manejar Java largo enteros en nuestros métodos nativos. Puesto que no está utilizando en esta aplicación, que no es gran pérdida. Simplemente vamos a modificar para cambiar el typedefs_md.h dos referencias a Int64 simplemente en int. Recuerde, sin embargo, que hacer esto hará que cualquier nativo de los métodos que utilizan enteros de 64 bits para romper. Las líneas en cuestión \ java \ include \ win32 \ typedefs_md.h son 

typedef __int64int64_t; 

Page 15: CAPÍTULO  16

15

VRML 2.0 con Java CAPÍTULO 16

typedef __int64 uint64_t sin firmar; 

Que se convierten en 

typedef int int64_t; typedef unsigned int uint64_t; 

Ahora intentar compilar de nuevo. Mucho mejor! Compilamos I6DImp.c de la misma manera: 

wcc386-bd I6DImp.c 

Hasta ahora, todo bien.

Paso Tres: Construir la biblioteca compartida 

A raíz de la designación en los archivos de ayuda Watcom, creamos un archivo llamado enlazador directiva Input6D.lnk que tiene este aspecto: 

sistema nt_dll InitInstance terminstance exportación Input6D_nativePoll exportación Input6D_nativeSetup biblioteca javai.lib archivo Input6D archivo I6DImp 

El javai.lib archivo es la biblioteca de rutinas de interfaz de Java que se utilizan métodos por los nativos. Ahora intenta vincular: 

wlink @ Input6D 

Y tenemos referencias sin resolver! Resulta que el compilador Watcom normalmente añade un guión bajo (_) al final de todos los símbolos externos, lo que significa que no coinciden correctamente con los símbolos que utiliza Java. Sin embargo, hay una solución: podemos añadir un # pragma a cada símbolo, para informar al compilador Watcom que no queremos que los símbolos mangling. Hay dos pragmas necesarias en I6DImp.c, uno para cada uno de los dos métodos nativos: 

# pragma Input6D_nativePoll a los "*" 

Page 16: CAPÍTULO  16

16

VRML 2.0 con Java CAPÍTULO 16

# pragma Input6D_nativeSetup a los "*" 

Observe que el método de nombres al comienzo con el nombre de la clase. Hay cuatro pragmas talones necesarios en el archivo, Input6D.c: 

# pragma Java_Input6D_nativeSetup_stub a los "*" # pragma Java_Input6D_nativePoll_stub a los "*" # pragma Input6D_nativeSetup a los "*" # pragma Input6D_nativePoll a los "*" 

Ahora podemos recompilar y enlace, y estamos casi allí. Hay un problema pendiente: una referencia a la pendiente makeJavaString () método. Poner \ java \ lib en la variable de entorno LIB permite al compilador Watcom encontrar el archivo javai.lib, y sabemos que makeJavaString () es de allí, así que ¿por qué el compilador no puede encontrar? 

La respuesta es que el archivo javai.lib está diseñado para el compilador de Microsoft, y estamos utilizando el compilador Watcom. Afortunadamente, la biblioteca de C Watcom utilidad puede leer un archivo DLL y crear una biblioteca: 

wlib javai.lib + \ java \ bin \ javai.dll 

Esto hace el truco. Ya no es necesario establecer la variable de LIB, y ahora podemos enlazar de nuevo y nuestra DLL. ¡Éxito! 

Aquí hay un makefile que hace todo el trabajo por nosotros: 

Input6D.dll: Input6D.obj I6DImp.obj javai.lib    wlink @ Input6D 

Input6D.obj: Input6D.c    wcc386-bd-5-i = f: \ java \ include-i = f: \ java \ include \ win32 Input6D.c 

I6DImp.obj: I6DImp.c Input6D.h    wcc386-bd-5-i = f: \ java \ include-i = f: \ java \ include \ win32 I6DImp.c 

Input6D.h: Input6D.class    javah Input6D 

Page 17: CAPÍTULO  16

17

VRML 2.0 con Java CAPÍTULO 16

Input6D.c: Input6D.class    javah-talones Input6D    copia + Input6D.c pragma tmp    copia tmp Input6D.c    del tmp 

Input6D.class: Input6D.java    javac Input6D.java javai.lib: \ java \ bin \ javai.dll    wlib javai + \ java \ bin \ javai.dll 

limpio:     del *. obj     del *. lib     del *. dll     del *. exe     del Input6D.c     del Input6D.h     del *. clase     del *.$$$$$$ 

Pragma el archivo sólo contiene las cuatro líneas que tenemos que añadir a la Input6D.c antes del inicio de la compilación. La definición de los prototipos 

Input6D nuestra clase puede ser aplicado directamente en los scripts de Java, y, de hecho, que a menudo la forma en que se utilizará. Por otra parte, ya que no sabe nada acerca de VRML, la clase es útil para una variedad de otras aplicaciones, también. 

Sin embargo, hay suficiente para los usos Input6D en VRML que tiene sentido para encapsular la funcionalidad en un prototipo. Nuestro PROTO hará más fácil para los constructores de todo el mundo simplemente para utilizar el nodo, sin tener que saber nada acerca de Java. 

El propio PROTO tiene este aspecto: 

# VRML V2.0 utf8 

Page 18: CAPÍTULO  16

18

VRML 2.0 con Java CAPÍTULO 16

PROTO Input6DOF [    SFInt32 campo puerto 0    campo SFBool accumulateTranslations FALSE    campo SFBool accumulateRotations FALSE    SFVec3f translationScale campo 1 1 1    campo SFVec3f rotationScale 3,14159 3,14159 3,14159    SFBool campo habilitado TRUE    eventIn SFBool set_enabled    eventIn SFBool set_accumulateTranslations    eventIn SFBool set_accumulateRotations    eventIn SFBool nivel    eventIn SFBool casa    eventIn SFTime pollTime    eventOut SFString descripción    eventOut SFVec3f posición    eventOut SFRotation orientación    eventOut SFInt32 botones    eventOut SFInt32 whichButton    eventOut SFBool button1    eventOut SFBool button2    eventOut SFBool Button3    eventOut SFBool button4    eventOut SFBool button5    eventOut SFBool button6    eventOut SFBool button7    eventOut SFBool button8 ] ( Script (    url "Read6DOF.class"    SFInt32 campo puerto es el puerto    campo SFBool accumulateTranslations ES accumulateTranslations    campo SFBool accumulateRotations ES accumulateRotations    campo SFVec3f translationScale ES translationScale    campo SFVec3f rotationScale ES rotationScale    SFBool campo habilitado está habilitado    eventIn SFBool set_enabled ES set_enabled    eventIn SFBool set_accumulateTranslations ES 

Page 19: CAPÍTULO  16

19

VRML 2.0 con Java CAPÍTULO 16

               set_accumulateTranslations    eventIn SFBool set_accumulateRotations ES                set_accumulateRotations    eventIn SFBool nivel es el nivel    eventIn SFBool casa es casa # profunda!    eventIn SFTime pollTime ES pollTime    eventOut SFString descripción descripción    eventOut SFVec3f posición es la posición    eventOut SFRotation orientación orientación    eventOut SFInt32 botones botones ES    eventOut SFInt32 whichButton ES whichButton    eventOut SFBool button1 ES button1    eventOut SFBool button2 ES button2    eventOut SFBool Button3 ES Button3    eventOut SFBool button4 ES button4    eventOut SFBool button5 ES button5    eventOut SFBool button6 ES button6    eventOut SFBool button7 ES button7    eventOut SFBool button8 ES button8    ) ) 

El PROTO resulta ser nada más que un nodo de secuencias de comandos, y se puede usar en cualquier lugar de comandos de un nodo que puede aparecer en un archivo VRML. 

Hay varios campos que son las mismas que las diversas variables de instancia de la clase Input6D: puerto, accumluateTranslations, acumular-Rotaciones, translationScale, y rotationScale. También hay habilitado un campo que controla si el sensor se activa Input6DOF-es decir, la generación de eventos. Hay eventIns para varios de estos campos. 

También hay eventIns para reajustar el sensor de orientación (nivel) y la traducción (en casa). Como se mencionó anteriormente, el nivel sólo tiene sentido si accumulateRotations es TRUE, y el hogar sólo tiene sentido si se acumulan-Translations es TRUE. 

Lo más importante eventIn es pollTime, lo que indica que es tiempo de tomar otra lectura. 

Page 20: CAPÍTULO  16

20

VRML 2.0 con Java CAPÍTULO 16

Esta ruta suele ser desde el momento de salida de un TimeSensor. 

El campo de descripción devuelto por el Input6D clase está disponible en la descripción eventOut. Todas las demás corresponden a eventOuts dinámicamente el cambio de valores: posición, orientación, y la situación de los botones. 

El botón de información de estado es muy útil y está disponible en una variedad de formas. Los botones eventOut es un entero de 32 bits con un bit por botón, lo que da a la mayoría de la información sino en la forma menos conveniente. Sin embargo, puede resultar útil para un desarrollador que quiere escribir un script que tiene acceso a toda la información del estado de botón. Tener en cuenta, por supuesto, que son muy pocos los dispositivos tendrán hasta en 32 botones. 

El whichButton eventOut da el número del botón que se presiona, más recientemente, y no en libertad. Si no se presiona el botón, el valor es cero, de lo contrario, es un botón de número a partir del 1. Este campo permite un número arbitrario de botones a utilizar, no sólo 32. El campo whichButton puede enviarse a la whichChoice ámbito de un nodo Switch, para seleccionar una representación de un objeto. El campo de enclavamiento, de ser verdad, hace que el último botón presionado a permanecer en el valor de whichButton el campo hasta que otro se pulsa el botón, de lo contrario, el campo vuelve a cero tan pronto como se suelta el botón. 

Y, por último, hay un eventOut para cada uno de los primeros ocho botones. Esto permite que los botones específicos para ser enviado a los distintos nodos. Se pueden utilizar para activar o desactivar las luces, va comenzar animaciones, y mucho más. Usted puede incluso VÍA eventOuts botón derecho a la Input6DOF nodo. Por ejemplo, puede VÍA un botón para el nivel eventIn a fin de que los niveles de apretar el botón del objeto. Puede VÍA accumulateTranslation a un botón para que pueda mover el punto de vista temporalmente lejos de la cabeza de tu avatar y regresar automáticamente al soltar el botón. Ideal para un "fuera del cuerpo" experiencia! El código de Java para el Nodo de secuencias de comandos 

Read6DOF El guión es muy sencillo. Hay una serie de variables de instancia que corresponden a campos en el prototipo, así como una inicializar () método que crea el objeto y Input6D establece sus campos sobre la base de los campos de la PROTO. También se referencia a los diversos eventOuts, ya vamos a estar usando un lote: 

/ / Guión de lectura 6 grados de libertad dispositivos de entrada 

Page 21: CAPÍTULO  16

21

VRML 2.0 con Java CAPÍTULO 16

/ / Escrito por Bernie Roehl, febrero de 1997 

importación vrml .*; importación vrml.node .*; importación vrml.field .*; 

clase pública se extiende Read6DOF Guión (    Input6D dispositivo;    boolean permitido;    booleano de enganche;    SFVec3f posición;    SFRotation orientación;    SFInt32 botones;    SFInt32 whichButton;    SFBool [] = buttonArray nuevo SFBool [8]; 

   public void inicializar () (    int puerto = ((SFInt32) getField ( "puerto")). getValue ();    dispositivo = new Input6D (puerto); 

   / / Establecer la acumulación de banderas    device.setAccumulateTranslations (     ((SFBool) getField ( "accumulateTranslations")). GetValue ());    device.setAccumulateRotations (     ((SFBool) getField ( "accumulateRotations")). GetValue ()); 

   / / Obtener la traducción escala    SFVec3f vec = (SFVec3f) getField ( "translationScale");    flotado [] = new escala flotado [3];    vec.getValue (escala);    device.setScaleX (escala [0]);    device.setScaleY (escala [1]);    device.setScaleZ (escala [2]); 

   / / Obtener la rotación escala    SFVec3f rvec = (SFVec3f) getField ( "rotationScale");    flotado [] = new rscale flotar [3]; 

Page 22: CAPÍTULO  16

22

VRML 2.0 con Java CAPÍTULO 16

   rvec.getValue (rscale);    device.setScaleR (rscale [0]);    device.setScaleU (rscale [1]);    device.setScaleV (rscale [2]); 

   / / Inicializa permitido bandera    habilitado = ((SFBool) getField ( "permitido")). getValue (); 

   / / Inicializar bandera de enganche    de enganche = ((SFBool) getField ( "enganche")). getValue (); 

   / / Establecer la descripción    SFString descripción = (SFString) getEventOut ( "descripción");    description.setValue (device.getDescription ()); 

   / / Obtener las referencias a la salida de los campos    posición = (SFVec3f) getEventOut ( "posición");    orientación = (SFRotation) getEventOut ( "orientación");    botones = (SFInt32) getEventOut ( "botones");    whichButton = (SFInt32) getEventOut ( "whichButton");    for (int i = 1; i <= 8; i)       buttonArray [i-1] = (SFBool) getEventOut ( "botón" i); ) 

También hay eventIns para reajustar el sensor de orientación (nivel) y la traducción (en casa). Como se mencionó anteriormente, el nivel sólo tiene sentido si accumulateRotations es TRUE, y el hogar sólo tiene sentido si se acumulan-Translations es TRUE. 

Lo más importante eventIn es pollTime, lo que indica que es tiempo de tomar otra lectura. Esta ruta suele ser desde el momento de salida de un TimeSensor. 

El campo de descripción devuelto por el Input6D clase está disponible en la descripción eventOut. Todas las demás corresponden a eventOuts dinámicamente el cambio de valores: posición, orientación, y la situación de los botones. 

Page 23: CAPÍTULO  16

23

VRML 2.0 con Java CAPÍTULO 16

El botón de información de estado es muy útil y está disponible en una variedad de formas. Los botones eventOut es un entero de 32 bits con un bit por botón, lo que da a la mayoría de la información sino en la forma menos conveniente. Sin embargo, puede resultar útil para un desarrollador que quiere escribir un script que tiene acceso a toda la información del estado de botón. Tener en cuenta, por supuesto, que son muy pocos los dispositivos tendrán hasta en 32 botones. 

El whichButton eventOut da el número del botón que se presiona, más recientemente, y no en libertad. Si no se presiona el botón, el valor es cero, de lo contrario, es un botón de número a partir del 1. Este campo permite un número arbitrario de botones a utilizar, no sólo 32. El campo whichButton puede enviarse a la whichChoice ámbito de un nodo Switch, para seleccionar una representación de un objeto. El campo de enclavamiento, de ser verdad, hace que el último botón presionado a permanecer en el valor de whichButton el campo hasta que otro se pulsa el botón, de lo contrario, el campo vuelve a cero tan pronto como se suelta el botón. 

Y, por último, hay un eventOut para cada uno de los primeros ocho botones. Esto permite que los botones específicos para ser enviado a los distintos nodos. Se pueden utilizar para activar o desactivar las luces, va comenzar animaciones, y mucho más. Usted puede incluso VÍA eventOuts botón derecho a la Input6DOF nodo. Por ejemplo, puede VÍA un botón para el nivel eventIn a fin de que los niveles de apretar el botón del objeto. Puede VÍA accumulateTranslation a un botón para que pueda mover el punto de vista temporalmente lejos de la cabeza de tu avatar y regresar automáticamente al soltar el botón. Ideal para un "fuera del cuerpo" experiencia! El código de Java para el Nodo de secuencias de comandos 

Read6DOF El guión es muy sencillo. Hay una serie de variables de instancia que corresponden a campos en el prototipo, así como una inicializar () método que crea el objeto y Input6D establece sus campos sobre la base de los campos de la PROTO. También se referencia a los diversos eventOuts, ya vamos a estar usando un lote: 

/ / Guión de lectura 6 grados de libertad dispositivos de entrada 

/ / Escrito por Bernie Roehl, febrero de 1997 

importación vrml .*; importación vrml.node .*; importación vrml.field .*; 

Page 24: CAPÍTULO  16

24

VRML 2.0 con Java CAPÍTULO 16

clase pública se extiende Read6DOF Guión (    Input6D dispositivo;    boolean permitido;    booleano de enganche;    SFVec3f posición;    SFRotation orientación;    SFInt32 botones;    SFInt32 whichButton;    SFBool [] = buttonArray nuevo SFBool [8]; 

   public void inicializar () (    int puerto = ((SFInt32) getField ( "puerto")). getValue ();    dispositivo = new Input6D (puerto); 

   / / Establecer la acumulación de banderas    device.setAccumulateTranslations (     ((SFBool) getField ( "accumulateTranslations")). GetValue ());    device.setAccumulateRotations (     ((SFBool) getField ( "accumulateRotations")). GetValue ()); 

   / / Obtener la traducción escala    SFVec3f vec = (SFVec3f) getField ( "translationScale");    flotado [] = new escala flotado [3];    vec.getValue (escala);    device.setScaleX (escala [0]);    device.setScaleY (escala [1]);    device.setScaleZ (escala [2]); 

   / / Obtener la rotación escala    SFVec3f rvec = (SFVec3f) getField ( "rotationScale");    flotado [] = new rscale flotar [3];    rvec.getValue (rscale);    device.setScaleR (rscale [0]);    device.setScaleU (rscale [1]);    device.setScaleV (rscale [2]); 

   / / Inicializa permitido bandera 

Page 25: CAPÍTULO  16

25

VRML 2.0 con Java CAPÍTULO 16

   habilitado = ((SFBool) getField ( "permitido")). getValue (); 

   / / Inicializar bandera de enganche    de enganche = ((SFBool) getField ( "enganche")). getValue (); 

   / / Establecer la descripción    SFString descripción = (SFString) getEventOut ( "descripción");    description.setValue (device.getDescription ()); 

   / / Obtener las referencias a la salida de los campos    posición = (SFVec3f) getEventOut ( "posición");    orientación = (SFRotation) getEventOut ( "orientación");    botones = (SFInt32) getEventOut ( "botones");    whichButton = (SFInt32) getEventOut ( "whichButton");    for (int i = 1; i <= 8; i)       buttonArray [i-1] = (SFBool) getEventOut ( "botón" i); ) 

El processEvent () método responde a pollTime eventIns tal y como era de esperar. Si el sensor no está habilitada, el pollTime los eventos son simplemente ignorados. En caso contrario, el dispositivo está encuestados y un control de errores. Si los valores han cambiado, processEvent () establece la nueva posición de la x, y, z los valores y leer desde el dispositivo. Se hace lo mismo para las rotaciones, pero ya hay más generales que participan, por primera vez controles para el caso de no común a todos los de rotación. De lo contrario, utiliza algunos quaternion rutinas para convertir los tres ángulos de rotación que se leen desde el dispositivo en el eje angular forma utilizada por SFRotations en VRML. Esta es la sobrecarga adicional que queremos evitar en todo caso los ángulos de cero. El código quaternion se describe más adelante en este capítulo: 

public void processEvent (Event ev) (    if (ev.getName (). es igual a ( "pollTime")) (       if (! permitido) / / no hacer nada si no nos permitió          retorno;       device.poll ();       if (device.getStatus ()! = 0) / / error de dispositivo          retorno;       if (device.hasChanged ()) (          position.setValue (            device.getX (), device.getY (), device.getZ ()); 

Page 26: CAPÍTULO  16

26

VRML 2.0 con Java CAPÍTULO 16

         r = device.getR flotador ();          u = device.getU flotador ();          v = device.getV flotador ();          if (r == 0 & & u == 0 & & v == 0) / / sin rotación             orientation.setValue (0, 0, 1, 0);          else (             Quaternion q = new quaternion (u, r, v);             orientation.setValue (q.toAxisAndAngle ());          )       )       if (device.buttonHasChanged ()) (          int b = device.getButtons ();          if (! enclavamiento | | device.getButtons ()! = 0)             whichButton.setValue (device.getButton ());          for (int i = 0; i <8; i)              buttonArray [i]. SetValue ((b & (1 <<i))! = 0);          buttons.setValue (device.getButtons ());       ) ) 

El botón de código se ejecuta sólo cuando el cambio realmente botones estado. Si estamos de enganche, nos fijamos el valor whichButton. También se que si un botón está presionado, incluso si no estamos de enganche. Las ocho salidas botón se establecen, como es el de 32-bit int que representa a todos los botones. 

Tenemos otros eventos de proceso, pero aviso que ponemos la pollTime primero en nuestro caso-si otra escalera. Esto se debe a que será de lejos la más común eventIn, por lo que tiene sentido para reducir al mínimo el tiempo de procesamiento de cheques de inmediato. 

El otro eventIns son bastante evidentes, ya que simplemente diferentes variables de instancia y / o llamar a los métodos de la Input6D objeto: 

  else if (ev.getName (). es igual a ( "permitido"))      habilitado = ((ConstSFBool) ev.getValue ()). getValue ();   else if (ev.getName (). es igual a ( "nivel")) (      / / Establecer todas las rotaciones a cero      si (((ConstSFBool) ev.getValue ()). getValue ()) (         device.setR (0);         device.setU (0);         device.setV (0);      )   ) 

Page 27: CAPÍTULO  16

27

VRML 2.0 con Java CAPÍTULO 16

  else if (ev.getName (). es igual a ( "casa")) (      / / Conjunto todas las traducciones a cero      si (((ConstSFBool) ev.getValue ()). getValue ()) (         device.setX (0);         device.setY (0);         device.setZ (0);      )   )   else if (ev.getName (). es igual a ( "set_accumulateTranslations")) (      device.setAccumulateTranslations (         ((ConstSFBool) ev.getValue ()). GetValue ());   )   else if (ev.getName (). es igual a ( "set_accumulateRotations")) (      device.setAccumulateRotations (         ((ConstSFBool) ev.getValue ()). GetValue ());   ) ) 

Cuaterniones 

Cuaterniones son interesantes objetos matemáticos, que se utilizan a menudo en gráficos por ordenador para representar a las rotaciones. Son más compactos que las matrices de rotación (cuatro valores en lugar de nueve) y en muchos casos son más eficientes. Asimismo, evitar la rotación de ciertos tipos de problemas, si eres curioso acerca de este tema, ver los gráficos de libros de texto para averiguar acerca de la "Gimbal candado" problema. 

     NOTA: Una descripción de las matemáticas detrás de cuaterniones es más allá del alcance de este libro, sino un texto estándar de gráficos, tales como gráficos de ordenador Principios y Práctica de Foley, van Dam, Feiner, y Hughs (Addison-Wesley, 1990), debería dar que todos los antecedentes que usted necesita. 

Cuaterniones son similares al eje angular de la representación de VRML, en el que hay un vector de tres elementos y un número que se corresponde con el ángulo. Ellos pueden ser fácilmente convertidos al eje angular de la forma y viceversa. Sin embargo, es mucho más fácil que se acumule el eje angular es la forma, que es la razón por la que está utilizando aquí.

Usted puede recordar que después de leer los tres ángulos de rotación del dispositivo de entrada, son convertidos a un quaternion y, a continuación, al eje angular forma: 

Quaternion q = new quaternion (u, r, v); 

Page 28: CAPÍTULO  16

28

VRML 2.0 con Java CAPÍTULO 16

orientation.setValue (q.toAxisAndAngle ()); 

Este hace uso de uno de los constructores quaternion disponible en nuestra clase: 

/ / Quaternion rutinas 

/ / Inspira en Gavin Bell rotation.c 

clase pública quaternion ( 

   flotado [] = new flotado valor [4]; 

   public String toString () (      valor devuelto [0] + "" + valor [1] + ""         + Valor [2] + "" + valor [3];    ) 

   público quaternion (float [] q) (      valor [0] = q [0]; valor [1] = q [1];      valor [2] = q [2], valor [3] = q [3];    ) 

   público quaternion (float [] eje, el ángulo de flotación) (      s = flotado (float) Math.sin (ángulo / 2);      for (int i = 0; i <3; + + i)        valor [i] = eje [i] * s;      valor [3] = (float) Math.cos (ángulo / 2);    ) 

   público quaternion (char eje, el ángulo de flotación) (      valor [3] = (float) Math.cos (ángulo / 2);      valor [0] = valor [1] = valor [2] = 0.0F;      switch (eje) (        case 'x': case 'X':          valor [0] = (float) Math.sin (ángulo / 2); break;        case 'y': case 'Y':          valor [1] = (float) Math.sin (ángulo / 2); break;        case 'z': case 'Z':          valor [2] = (float) Math.sin (ángulo / 2); break;    ) ) 

Page 29: CAPÍTULO  16

29

VRML 2.0 con Java CAPÍTULO 16

   público quaternion (guiñada flotador, float pitch, float roll) (      Quaternion q;      if (guiñada! = 0) (       q = new quaternion ( 'Y', de orientación);       if (campo! = 0)          q.multiply (nuevo quaternion ( 'X', tono));       if (roll! = 0)          q.multiply (nuevo quaternion ( 'Z' roll));    )    else if (paso! = 0) (       q = new quaternion ( 'X', brea);       if (roll! = 0)          q.multiply (nuevo quaternion ( 'Z' roll));    )    algo más       q = new quaternion ( 'Z' roll);       valor [0] = q.value [0]; valor [1] = q.value [1];       valor [2] = q.value [2], valor [3] = q.value [3];    ) 

El quaternion clase contiene una serie de cuatro flotadores para almacenar el quaternion sí mismo. El primer constructor de llena en estos cuatro valores directamente. El segundo eje-convierte un ángulo de la representación en un quaternion. La tercera se refiere brevemente a los tres casos más comunes: la rotación sobre una de las x, y, z o ejes. El cuarto y último constructor, que es la que usamos en Read6DOF, tiene los tres ángulos de rotación y las aplica en el orden de orientación, tono, rollo (es decir, gira alrededor de la x, y, z o ejes). Lo hace mediante la construcción de cuaterniones y multiplicando cada uno de ellos juntos. El código se ha estructurado a fin de evitar la multiplicación cuando no es necesario, que es de nuevo un examen de eficiencia, ya que la multiplicación de código es bastante complejo e implica un gran número de múltiplos: 

multiplicar vacío (quaternion q) (    flotado [] tmp = new flotar [4];    tmp [0] = q.value [3] * valor [0] + q.value [0] * valor [3]        + Q.value [1] * valor [2] - q.value [2] * valor [1];    tmp [1] = q.value [3] * valor [1] + q.value [1] * valor [3]        + Q.value [2] * valor [0] - q.value [0] * valor [2];    tmp [2] = q.value [3] * valor [2] + q.value [2] * valor [3]        + Q.value [0] * valor [1] - q.value [1] * valor [0];    tmp [3] = q.value [3] * valor [3] - q.value [0] * valor [0]        - Q.value [1] * valor [1] - q.value [2] * valor [2];    valor [0] = tmp [0]; valor [1] = tmp [1]; 

Page 30: CAPÍTULO  16

30

VRML 2.0 con Java CAPÍTULO 16

   valor [2] = tmp [2], valor [3] = tmp [3]; ) 

El último método en nuestra clase quaternion es el que convierte en un eje quaternion forma de ángulo: 

público flotar [] toAxisAndAngle () (    flotado [] = new flotado bis [4];    aa [3] = (float) Math.acos (valor [3]) * 2;    s = flotado (float) Math.sin (aa [3] / 2);    for (int i = 0; i <3; + + i)       aa [i] = valor [i] / s;    regresar aa; ) 

Esto es sólo la inversa de la operación que se utilizó en el segundo constructor.

Una muestra del archivo 

El siguiente archivo VRML te da una idea de los diversos usos de los Input6DOF nodo. Está destinado a servir como punto de partida para sus proyectos; descomentar las distintas vías, al final del archivo para ver lo que hacen: 

# VRML V2.0 utf8 

EXTERNPROTO Input6DOF [    SFInt32 campo puerto    SFBool accumulateTranslations campo    SFBool accumulateRotations campo    SFVec3f translationScale campo    SFVec3f rotationScale campo    SFBool campo habilitado    SFBool campo de enclavamiento    eventIn SFBool set_enabled    eventIn SFBool set_accumulateTranslations    eventIn SFBool set_accumulateRotations    eventIn SFBool nivel    eventIn SFBool casa    eventIn SFTime pollTime    eventOut SFString descripción 

Page 31: CAPÍTULO  16

31

VRML 2.0 con Java CAPÍTULO 16

   eventOut SFVec3f posición    eventOut SFRotation orientación    eventOut SFInt32 botones    eventOut SFInt32 whichButton    eventOut SFBool button1    eventOut SFBool button2    eventOut SFBool Button3    eventOut SFBool button4    eventOut SFBool button5    eventOut SFBool button6    eventOut SFBool button7    eventOut SFBool button8 ] "Input6DOF.wrl" 

DEF NI NavigationInfo () 

Punto de vista de la posición (0 0 10) 

DirectionalLight (dirección -1 0 0) 

DEF TS TimeSensor (bucle TRUE) 

Transformar (DEF TR   niños pequeños     DEF SW Switch (      whichChoice 0      elección [        (Grupo)        Forma (          Un aspecto DEF Aspecto (            material Material (diffuseColor 1 0 0)          )          geometría recuadro ()        )        Forma (Un aspecto USO geometría Esfera ())        Forma (Un aspecto USO geometría Cilindro ())        Forma (Un aspecto USO geometría Cono ())      ]     ) ) # (DEF SENSOR Input6DOF # AccumulateRotations TRUE 

Page 32: CAPÍTULO  16

32

VRML 2.0 con Java CAPÍTULO 16

# RotationScale .314159 .314159 .314159 #) 

DEF SENSOR Input6DOF (   accumulateTranslations TRUE   translationScale .314159 .314159 .314159 # Enclavamiento TRUE ) 

VÍA TS.time A SENSOR.pollTime VÍA SENSOR.position A TR.translation VÍA SENSOR.orientation A TR.rotation VÍA SENSOR.whichButton A SW.whichChoice # SENSOR.button2 VÍA A SENSOR.accumulateTranslations # SENSOR.button3 VÍA A SENSOR.home 

Problemas de rendimiento y disponibilidad 

Hay dos cuestiones importantes a considerar cuando se utiliza este código: rendimiento y disponibilidad. 

El rendimiento es una cuestión cada vez que usan Java. El código no se presenta aquí la mayor parte del trabajo en Java, en aras de la portabilidad. La ventaja es que un desarrollador puede añadir soporte para un nuevo dispositivo simplemente escribir un par de 10-línea C funciones. La desventaja es que la sobrecarga de uso de Java puede ser un problema, especialmente en áreas críticas de latencia-como cabeza de seguimiento. 

Hay varias cosas que podríamos hacer para mejorar el rendimiento. Puesto que está utilizando métodos nativos de todos modos, no se había ningún daño en la aplicación del código en C. quaternion De hecho, gran parte de la funcionalidad de Input6D.java podría ser trasladado a C, aunque no está claro cuánto de una ganancia de rendimiento en realidad resultado. 

La disponibilidad cuestión deriva del hecho de que el modelo de seguridad utilizado en la mayoría de los navegadores Web puede evitar el uso de métodos a todos los nativos. Los ejemplos en este capítulo se probaron utilizando la versión independiente de la realidad de líquidos, y puede que no funcionen en un VRML plug-in para un navegador Web. Por supuesto, si estás utilizando un dispositivo de entrada de 6 DOF, las probabilidades son que usted está usando Netscape algo distinto de todos modos. 

Otro aspecto de la disponibilidad que es un motivo de preocupación es el hecho de que no todas las máquinas virtuales Java de manejar los métodos nativos de la misma manera. Concretamente, el código compilado bajo el sol JDK 1.0.2 no funciona con la máquina virtual de Microsoft, y 

Page 33: CAPÍTULO  16

33

VRML 2.0 con Java CAPÍTULO 16

viceversa. La única solución en este momento es compilar en dos ocasiones y que el usuario instale el correcto para su navegador. Tenga en cuenta que algunos navegadores (como líquido realidad, que se utilizó para probar el código en este capítulo) están disponibles en dos versiones: una que utiliza el JDK de Sun y uno que utiliza Microsoft. 

La verdadera solución a ambos problemas es que el nodo Input6DOF que se construirán en el propio navegador de VRML. Ya no sería necesario VÍA eventos pollTime a la entrada, ya que el navegador se aseguraría de que el nodo responde cada vez que el dispositivo de entrada cambia de estado. Los gastos generales sería eliminado, ya que el dispositivo de apoyo sería en código nativo. El problema de seguridad también desaparecer, ya que no DLL locales tendría que ser cargado. Orientación futura 

El código presentado en este capítulo está diseñado para hacer más fácil para usted para apoyar DOF 6 dispositivos de entrada en las aplicaciones Java y mundos VRML. 

Si encuentra útil este código, o si el apoyo para desarrollar otros dispositivos u otras plataformas, por favor, mándenme una línea (mi dirección de correo electrónico está [email protected]). La última versión de este código, y los otros proyectos de este libro, se puede encontrar en mi sitio Web: http://ece.uwaterloo.ca/ ~ broehl / vrml.