// Include vrpn_Shared.h _first_ to avoid conflicts with sys/time.h // and unistd.h #include <math.h> // for sqrt #include <stdio.h> // for fprintf, stderr, NULL, etc #include "vrpn_Connection.h" // for vrpn_Connection, etc #include "vrpn_Shared.h" // for vrpn_buffer, vrpn_unbuffer, etc #if defined(linux) || defined(__sparc) || defined(hpux) || defined(__GNUC__) #include <string.h> // for memcpy #endif #include <quat.h> // for q_matrix_type, etc #include "vrpn_ForceDevice.h" /* cheezy hack to make sure this enum is defined in the case we didn't include trimesh.h */ #ifndef TRIMESH_H // the different types of trimeshes we have available for haptic display enum TrimeshType { GHOST, HCOLLIDE }; #endif #define CHECK(a) \ if (a == -1) return -1 #if 0 // c = a x b static void vector_cross (const vrpn_float64 a [3], const vrpn_float64 b [3], vrpn_float64 c [3]) { c[0] = a[1] * b[2] - a[2] * b[1]; c[1] = a[2] * b[0] - a[0] * b[2]; c[2] = a[0] * b[1] - a[1] * b[0]; } // vprime = v * T static void rotate_vector (const vrpn_float64 v [3], const vrpn_float64 T [9], vrpn_float64 vprime [3]) { vprime[0] = v[0] * T[0] + v[1] * T[3] + v[2] * T[6]; vprime[1] = v[0] * T[1] + v[1] * T[4] + v[2] * T[7]; vprime[2] = v[0] * T[2] + v[1] * T[5] + v[2] * T[8]; } static vrpn_float64 vector_dot (const vrpn_float64 a [3], const vrpn_float64 b [3]) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; } #endif vrpn_ForceDevice::vrpn_ForceDevice(const char *name, vrpn_Connection *c) : vrpn_BaseClass(name, c) { vrpn_BaseClass::init(); // set the current time to zero timestamp.tv_sec = 0; timestamp.tv_usec = 0; // set the force to zero // d_force[0] = d_force[1] = d_force[2] = 0.0; SurfaceKspring = 0.8f; SurfaceFdynamic = 0.3f; SurfaceFstatic = 0.7f; SurfaceKdamping = 0.001f; numRecCycles = 1; errorCode = FD_OK; SurfaceKadhesionNormal = 0.0001f; SurfaceKadhesionLateral = 0.0002f; SurfaceBuzzFreq = 0.0003f; SurfaceBuzzAmp = 0.0004f; SurfaceTextureWavelength = 0.01f; SurfaceTextureAmplitude = 0.0005f; // ajout ONDIM customEffectId = -1; customEffectParams = NULL; nbCustomEffectParams = 0; // fin ajout ONDIM } // ajout ONDIM void vrpn_ForceDevice::setCustomEffect(vrpn_int32 effectId, vrpn_float32 *params, vrpn_uint32 nbParams) { customEffectId = effectId; if (customEffectParams != NULL) { delete[] customEffectParams; } customEffectParams = new vrpn_float32[nbParams]; memcpy(customEffectParams, params, sizeof(vrpn_float32) * nbParams); nbCustomEffectParams = nbParams; } // fin ajout ondim int vrpn_ForceDevice::register_types(void) { force_message_id = d_connection->register_message_type("vrpn_ForceDevice Force"); forcefield_message_id = d_connection->register_message_type("vrpn_ForceDevice Force_Field"); plane_message_id = d_connection->register_message_type("vrpn_ForceDevice Plane"); plane_effects_message_id = d_connection->register_message_type("vrpn_ForceDevice Plane2"); addObject_message_id = d_connection->register_message_type("vrpn_ForceDevice addObject"); addObjectExScene_message_id = d_connection->register_message_type( "vrpn_ForceDevice addObjectExScene"); moveToParent_message_id = d_connection->register_message_type("vrpn_ForceDevice moveToParent"); setObjectPosition_message_id = d_connection->register_message_type( "vrpn_ForceDevice setObjectPosition"); setObjectOrientation_message_id = d_connection->register_message_type( "vrpn_ForceDevice setObjectOrientation"); setObjectScale_message_id = d_connection->register_message_type("vrpn_ForceDevice setObjectScale"); removeObject_message_id = d_connection->register_message_type("vrpn_ForceDevice removeObject"); setVertex_message_id = d_connection->register_message_type("vrpn_ForceDevice setVertex"); setNormal_message_id = d_connection->register_message_type("vrpn_ForceDevice setNormal"); setTriangle_message_id = d_connection->register_message_type("vrpn_ForceDevice setTriangle"); removeTriangle_message_id = d_connection->register_message_type("vrpn_ForceDevice removeTriangle"); updateTrimeshChanges_message_id = d_connection->register_message_type( "vrpn_ForceDevice updateTrimeshChanges"); transformTrimesh_message_id = d_connection->register_message_type( "vrpn_ForceDevice transformTrimesh"); setTrimeshType_message_id = d_connection->register_message_type("vrpn_ForceDevice setTrimeshType"); clearTrimesh_message_id = d_connection->register_message_type("vrpn_ForceDevice clearTrimesh"); setHapticOrigin_message_id = d_connection->register_message_type("vrpn_ForceDevice setHapticOrigin"); setHapticScale_message_id = d_connection->register_message_type("vrpn_ForceDevice setHapticScale"); setSceneOrigin_message_id = d_connection->register_message_type("vrpn_ForceDevice setSceneOrigin"); getNewObjectID_message_id = d_connection->register_message_type("vrpn_ForceDevice getNewObjectID"); setObjectIsTouchable_message_id = d_connection->register_message_type( "vrpn_ForceDevice setObjectIsTouchable"); scp_message_id = d_connection->register_message_type("vrpn_ForceDevice SCP"); error_message_id = d_connection->register_message_type("vrpn_ForceDevice Force_Error"); enableConstraint_message_id = d_connection->register_message_type( "vrpn_ForceDevice constraint_enable"); setConstraintMode_message_id = d_connection->register_message_type("vrpn_ForceDevice constraint_mode"); setConstraintPoint_message_id = d_connection->register_message_type( "vrpn_ForceDevice constraint_point"); setConstraintLinePoint_message_id = d_connection->register_message_type( "vrpn_ForceDevice constraint_linept"); setConstraintLineDirection_message_id = d_connection->register_message_type( "vrpn_ForceDevice constraint_linedir"); setConstraintPlanePoint_message_id = d_connection->register_message_type("vrpn_ForceDevice constraint_plpt"); setConstraintPlaneNormal_message_id = d_connection->register_message_type( "vrpn_ForceDevice constraint_plnorm"); setConstraintKSpring_message_id = d_connection->register_message_type( "vrpn_ForceDevice constraint_KSpring"); // ajout ONDIM custom_effect_message_id = d_connection->register_message_type("vrpn_ForceDevice Custom Effect"); // fin ajout ONDIM return 0; } // virtual vrpn_ForceDevice::~vrpn_ForceDevice(void) { if (customEffectParams != NULL) { delete[] customEffectParams; } } void vrpn_ForceDevice::print_plane(void) { printf("plane: %f, %f, %f, %f\n", plane[0], plane[1], plane[2], plane[3]); } void vrpn_ForceDevice::print_report(void) { // Nothing sets d_force any more! printf("Timestamp:%ld:%ld\n", timestamp.tv_sec, static_cast<long>(timestamp.tv_usec)); // printf("Force :%lf, %lf, %lf\n", d_force[0],d_force[1],d_force[2]); } // static char *vrpn_ForceDevice::encode_force(vrpn_int32 &length, const vrpn_float64 *force) { // Message includes: vrpn_float64 force[3] // Byte order of each needs to be reversed to match network standard int i; char *buf; char *mptr; vrpn_int32 mlen; length = 3 * sizeof(vrpn_float64); mlen = length; buf = new char[length]; mptr = buf; // Move the force there for (i = 0; i < 3; i++) { vrpn_buffer(&mptr, &mlen, force[i]); } return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_force(const char *buffer, const vrpn_int32 len, vrpn_float64 *force) { int i; const char *mptr = buffer; if (len != (3 * sizeof(vrpn_float64))) { fprintf(stderr, "vrpn_ForceDevice: force message payload error\n"); fprintf(stderr, " (got %d, expected %lud)\n", len, static_cast<unsigned long>(3 * sizeof(vrpn_float64))); return -1; } for (i = 0; i < 3; i++) CHECK(vrpn_unbuffer(&mptr, &(force[i]))); return 0; } // ajout ONDIM char *vrpn_ForceDevice::encode_custom_effect(vrpn_int32 &len, vrpn_uint32 effectId, const vrpn_float32 *params, vrpn_uint32 nbParams) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_uint32) * 2 + nbParams * sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, effectId); vrpn_buffer(&mptr, &mlen, nbParams); for (unsigned int i = 0; i < nbParams; i++) { vrpn_buffer(&mptr, &mlen, params[i]); } return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_custom_effect(const char *buffer, const vrpn_int32 len, vrpn_uint32 *effectId, vrpn_float32 **params, vrpn_uint32 *nbParams) { const char *mptr = buffer; // OutputDebugString("decoding custom effect\n"); if (static_cast<size_t>(len) < (sizeof(vrpn_uint32) * 2)) { fprintf(stderr, "vrpn_ForceDevice: custom effect message payload error\n"); fprintf(stderr, " (got %d, expected at least %lud)\n", len, static_cast<unsigned long>(2 * sizeof(vrpn_uint32))); return -1; } CHECK(vrpn_unbuffer(&mptr, effectId)); CHECK(vrpn_unbuffer(&mptr, nbParams)); if ((vrpn_uint32)(len) < (2 * sizeof(vrpn_uint32) + (*nbParams) * sizeof(vrpn_float32))) { fprintf(stderr, "vrpn_ForceDevice: custom effect message payload error\n"); fprintf(stderr, " (got %d, expected at least %lud)\n", len, static_cast<unsigned long>(2 * sizeof(vrpn_uint32) + (*nbParams) * sizeof(vrpn_float32))); return -2; } if (*params != NULL) delete[] * params; *params = new vrpn_float32[(*nbParams)]; for (vrpn_uint32 i = 0; i < (*nbParams); i++) { CHECK(vrpn_unbuffer(&mptr, &((*params)[i]))); } return 0; } // fin ajout ONDIM // static char *vrpn_ForceDevice::encode_scp(vrpn_int32 &length, const vrpn_float64 *pos, const vrpn_float64 *quat) { int i; char *buf; char *mptr; vrpn_int32 mlen; length = 7 * sizeof(vrpn_float64); mlen = length; buf = new char[length]; mptr = buf; for (i = 0; i < 3; i++) { vrpn_buffer(&mptr, &mlen, pos[i]); } for (i = 0; i < 4; i++) { vrpn_buffer(&mptr, &mlen, quat[i]); } return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_scp(const char *buffer, const vrpn_int32 len, vrpn_float64 *pos, vrpn_float64 *quat) { int i; const char *mptr = buffer; int desiredLen = 7 * sizeof(vrpn_float64); if (len != desiredLen) { fprintf(stderr, "vrpn_ForceDevice: scp message payload error\n"); fprintf(stderr, " (got %d, expected %d)\n", len, desiredLen); return -1; } for (i = 0; i < 3; i++) CHECK(vrpn_unbuffer(&mptr, &(pos[i]))); for (i = 0; i < 4; i++) CHECK(vrpn_unbuffer(&mptr, &(quat[i]))); return 0; } // static char *vrpn_ForceDevice::encode_plane( vrpn_int32 &len, const vrpn_float32 *plane, const vrpn_float32 kspring, const vrpn_float32 kdamp, const vrpn_float32 fdyn, const vrpn_float32 fstat, const vrpn_int32 plane_index, const vrpn_int32 n_rec_cycles) { // Message includes: vrpn_float32 plane[4], int i; char *buf; char *mptr; vrpn_int32 mlen; len = 8 * sizeof(vrpn_float32) + 2 * sizeof(vrpn_int32); mlen = len; buf = new char[len]; mptr = buf; for (i = 0; i < 4; i++) { vrpn_buffer(&mptr, &mlen, plane[i]); } vrpn_buffer(&mptr, &mlen, kspring); vrpn_buffer(&mptr, &mlen, kdamp); vrpn_buffer(&mptr, &mlen, fdyn); vrpn_buffer(&mptr, &mlen, fstat); vrpn_buffer(&mptr, &mlen, plane_index); vrpn_buffer(&mptr, &mlen, n_rec_cycles); return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_plane( const char *buffer, const vrpn_int32 len, vrpn_float32 *plane, vrpn_float32 *kspring, vrpn_float32 *kdamp, vrpn_float32 *fdyn, vrpn_float32 *fstat, vrpn_int32 *plane_index, vrpn_int32 *n_rec_cycles) { int i; const char *mptr = buffer; if (len != 8 * sizeof(vrpn_float32) + 2 * sizeof(vrpn_int32)) { fprintf(stderr, "vrpn_ForceDevice: plane message payload error\n"); fprintf(stderr, " (got %d, expected %lud)\n", len, static_cast<unsigned long>(8 * sizeof(vrpn_float32) + 2 * sizeof(vrpn_int32))); return -1; } for (i = 0; i < 4; i++) CHECK(vrpn_unbuffer(&mptr, &(plane[i]))); CHECK(vrpn_unbuffer(&mptr, kspring)); CHECK(vrpn_unbuffer(&mptr, kdamp)); CHECK(vrpn_unbuffer(&mptr, fdyn)); CHECK(vrpn_unbuffer(&mptr, fstat)); CHECK(vrpn_unbuffer(&mptr, plane_index)); CHECK(vrpn_unbuffer(&mptr, n_rec_cycles)); return 0; } // static char *vrpn_ForceDevice::encode_surface_effects( vrpn_int32 &len, const vrpn_float32 k_adhesion_normal, const vrpn_float32 k_adhesion_lateral, const vrpn_float32 tex_amp, const vrpn_float32 tex_wl, const vrpn_float32 buzz_amp, const vrpn_float32 buzz_freq) { char *buf; char *mptr; vrpn_int32 mlen; len = 6 * sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, k_adhesion_normal); vrpn_buffer(&mptr, &mlen, k_adhesion_lateral); vrpn_buffer(&mptr, &mlen, tex_amp); vrpn_buffer(&mptr, &mlen, tex_wl); vrpn_buffer(&mptr, &mlen, buzz_amp); vrpn_buffer(&mptr, &mlen, buzz_freq); return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_surface_effects( const char *buffer, const vrpn_int32 len, vrpn_float32 *k_adhesion_normal, vrpn_float32 *k_adhesion_lateral, vrpn_float32 *tex_amp, vrpn_float32 *tex_wl, vrpn_float32 *buzz_amp, vrpn_float32 *buzz_freq) { const char *mptr = buffer; if (len != 6 * sizeof(vrpn_float32)) { fprintf(stderr, "vrpn_ForceDevice: surface effects message payload "); fprintf(stderr, "error\n (got %d, expected %lud)\n", len, static_cast<unsigned long>(6 * sizeof(vrpn_float32))); return -1; } CHECK(vrpn_unbuffer(&mptr, k_adhesion_normal)); CHECK(vrpn_unbuffer(&mptr, k_adhesion_lateral)); CHECK(vrpn_unbuffer(&mptr, tex_amp)); CHECK(vrpn_unbuffer(&mptr, tex_wl)); CHECK(vrpn_unbuffer(&mptr, buzz_amp)); CHECK(vrpn_unbuffer(&mptr, buzz_freq)); return 0; } // static char *vrpn_ForceDevice::encode_vertex(vrpn_int32 &len, const vrpn_int32 objNum, const vrpn_int32 vertNum, const vrpn_float32 x, const vrpn_float32 y, const vrpn_float32 z) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(objNum) + sizeof(vertNum) + 3 * sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); vrpn_buffer(&mptr, &mlen, vertNum); vrpn_buffer(&mptr, &mlen, x); vrpn_buffer(&mptr, &mlen, y); vrpn_buffer(&mptr, &mlen, z); return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_vertex(const char *buffer, const vrpn_int32 len, vrpn_int32 *objNum, vrpn_int32 *vertNum, vrpn_float32 *x, vrpn_float32 *y, vrpn_float32 *z) { const char *mptr = buffer; if (len != (sizeof(objNum) + sizeof(vertNum) + 3 * sizeof(vrpn_float32))) { fprintf(stderr, "vrpn_ForceDevice: vertex message payload error\n"); fprintf(stderr, " (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(objNum) + sizeof(vertNum) + 3 * sizeof(vrpn_float32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); CHECK(vrpn_unbuffer(&mptr, vertNum)); CHECK(vrpn_unbuffer(&mptr, x)); CHECK(vrpn_unbuffer(&mptr, y)); CHECK(vrpn_unbuffer(&mptr, z)); return 0; } // static char *vrpn_ForceDevice::encode_normal(vrpn_int32 &len, const vrpn_int32 objNum, const vrpn_int32 normNum, const vrpn_float32 x, const vrpn_float32 y, const vrpn_float32 z) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32) + sizeof(vrpn_int32) + 3 * sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); vrpn_buffer(&mptr, &mlen, normNum); vrpn_buffer(&mptr, &mlen, x); vrpn_buffer(&mptr, &mlen, y); vrpn_buffer(&mptr, &mlen, z); return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_normal(const char *buffer, const vrpn_int32 len, vrpn_int32 *objNum, vrpn_int32 *vertNum, vrpn_float32 *x, vrpn_float32 *y, vrpn_float32 *z) { const char *mptr = buffer; if (len != (sizeof(vrpn_int32) + sizeof(vrpn_int32) + 3 * sizeof(vrpn_float32))) { fprintf(stderr, "vrpn_ForceDevice: normal message payload error\n"); fprintf(stderr, " (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32) + sizeof(vrpn_int32) + 3 * sizeof(vrpn_float32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); CHECK(vrpn_unbuffer(&mptr, vertNum)); CHECK(vrpn_unbuffer(&mptr, x)); CHECK(vrpn_unbuffer(&mptr, y)); CHECK(vrpn_unbuffer(&mptr, z)); return 0; } // static char *vrpn_ForceDevice::encode_triangle( vrpn_int32 &len, const vrpn_int32 objNum, const vrpn_int32 triNum, const vrpn_int32 vert0, const vrpn_int32 vert1, const vrpn_int32 vert2, const vrpn_int32 norm0, const vrpn_int32 norm1, const vrpn_int32 norm2) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32) + 7 * sizeof(vrpn_int32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); vrpn_buffer(&mptr, &mlen, triNum); vrpn_buffer(&mptr, &mlen, vert0); vrpn_buffer(&mptr, &mlen, vert1); vrpn_buffer(&mptr, &mlen, vert2); vrpn_buffer(&mptr, &mlen, norm0); vrpn_buffer(&mptr, &mlen, norm1); vrpn_buffer(&mptr, &mlen, norm2); return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_triangle( const char *buffer, const vrpn_int32 len, vrpn_int32 *objNum, vrpn_int32 *triNum, vrpn_int32 *vert0, vrpn_int32 *vert1, vrpn_int32 *vert2, vrpn_int32 *norm0, vrpn_int32 *norm1, vrpn_int32 *norm2) { const char *mptr = buffer; if (len != (sizeof(vrpn_int32) + 7 * sizeof(vrpn_int32))) { fprintf(stderr, "vrpn_ForceDevice: triangle message payload error\n"); fprintf(stderr, " (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32) + 7 * sizeof(vrpn_int32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); CHECK(vrpn_unbuffer(&mptr, triNum)); CHECK(vrpn_unbuffer(&mptr, vert0)); CHECK(vrpn_unbuffer(&mptr, vert1)); CHECK(vrpn_unbuffer(&mptr, vert2)); CHECK(vrpn_unbuffer(&mptr, norm0)); CHECK(vrpn_unbuffer(&mptr, norm1)); CHECK(vrpn_unbuffer(&mptr, norm2)); return 0; } // static char *vrpn_ForceDevice::encode_removeTriangle(vrpn_int32 &len, const vrpn_int32 objNum, const vrpn_int32 triNum) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32) + sizeof(vrpn_int32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); vrpn_buffer(&mptr, &mlen, triNum); return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_removeTriangle(const char *buffer, const vrpn_int32 len, vrpn_int32 *objNum, vrpn_int32 *triNum) { const char *mptr = buffer; if (len != (sizeof(vrpn_int32) + sizeof(vrpn_int32))) { fprintf(stderr, "vrpn_ForceDevice: remove triangle message payload"); fprintf(stderr, " error\n (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32) + sizeof(vrpn_int32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); CHECK(vrpn_unbuffer(&mptr, triNum)); return 0; } // static // this is where we send down our surface parameters char *vrpn_ForceDevice::encode_updateTrimeshChanges( vrpn_int32 &len, const vrpn_int32 objNum, const vrpn_float32 kspring, const vrpn_float32 kdamp, const vrpn_float32 fstat, const vrpn_float32 fdyn) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32) + 4 * sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); vrpn_buffer(&mptr, &mlen, kspring); vrpn_buffer(&mptr, &mlen, kdamp); vrpn_buffer(&mptr, &mlen, fstat); vrpn_buffer(&mptr, &mlen, fdyn); return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_updateTrimeshChanges( const char *buffer, const vrpn_int32 len, vrpn_int32 *objNum, vrpn_float32 *kspring, vrpn_float32 *kdamp, vrpn_float32 *fstat, vrpn_float32 *fdyn) { const char *mptr = buffer; if (len != (sizeof(vrpn_int32) + 4 * sizeof(vrpn_float32))) { fprintf(stderr, "vrpn_ForceDevice: update trimesh message payload"); fprintf(stderr, " error\n (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32) + 4 * sizeof(vrpn_float32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); CHECK(vrpn_unbuffer(&mptr, kspring)); CHECK(vrpn_unbuffer(&mptr, kdamp)); CHECK(vrpn_unbuffer(&mptr, fstat)); CHECK(vrpn_unbuffer(&mptr, fdyn)); return 0; } // static char *vrpn_ForceDevice::encode_setTrimeshType(vrpn_int32 &len, const vrpn_int32 objNum, const vrpn_int32 type) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32) + sizeof(vrpn_int32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); vrpn_buffer(&mptr, &mlen, type); return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_setTrimeshType(const char *buffer, const vrpn_int32 len, vrpn_int32 *objNum, vrpn_int32 *type) { const char *mptr = buffer; if (len != (sizeof(vrpn_int32) + sizeof(vrpn_int32))) { fprintf(stderr, "vrpn_ForceDevice: trimesh type message payload"); fprintf(stderr, " error\n (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32) + sizeof(vrpn_int32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); CHECK(vrpn_unbuffer(&mptr, type)); return 0; } // static char *vrpn_ForceDevice::encode_trimeshTransform( vrpn_int32 &len, const vrpn_int32 objNum, const vrpn_float32 homMatrix[16]) { int i; char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32) + 16 * sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); for (i = 0; i < 16; i++) vrpn_buffer(&mptr, &mlen, homMatrix[i]); return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_trimeshTransform(const char *buffer, const vrpn_int32 len, vrpn_int32 *objNum, vrpn_float32 homMatrix[16]) { int i; const char *mptr = buffer; if (len != (sizeof(vrpn_int32) + 16 * sizeof(vrpn_float32))) { fprintf(stderr, "vrpn_ForceDevice: trimesh transform message payload "); fprintf(stderr, "error\n (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32) + 16 * sizeof(vrpn_float32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); for (i = 0; i < 16; i++) CHECK(vrpn_unbuffer(&mptr, &(homMatrix[i]))); return 0; } char *vrpn_ForceDevice::encode_addObject(vrpn_int32 &len, const vrpn_int32 objNum, const vrpn_int32 ParentNum) { char *buf; char *mptr; vrpn_int32 mlen; len = 2 * sizeof(vrpn_int32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); vrpn_buffer(&mptr, &mlen, ParentNum); return buf; } vrpn_int32 vrpn_ForceDevice::decode_addObject(const char *buffer, vrpn_int32 len, vrpn_int32 *objNum, vrpn_int32 *ParentNum) { const char *mptr = buffer; if (len != 2 * sizeof(vrpn_int32)) { fprintf(stderr, "vrpn_ForceDevice: add object message payload "); fprintf(stderr, "error\n (got %d, expected %lud)\n", len, static_cast<unsigned long>(2 * sizeof(vrpn_int32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); CHECK(vrpn_unbuffer(&mptr, ParentNum)); return 0; } char *vrpn_ForceDevice::encode_addObjectExScene(vrpn_int32 &len, const vrpn_int32 objNum) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(objNum); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); return buf; } vrpn_int32 vrpn_ForceDevice::decode_addObjectExScene(const char *buffer, vrpn_int32 len, vrpn_int32 *objNum) { const char *mptr = buffer; if (len != sizeof(vrpn_int32)) { fprintf(stderr, "vrpn_ForceDevice: add object message payload "); fprintf(stderr, "error\n (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); return 0; } char *vrpn_ForceDevice::encode_objectPosition(vrpn_int32 &len, const vrpn_int32 objNum, const vrpn_float32 Pos[3]) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32) + 3 * sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); vrpn_buffer(&mptr, &mlen, Pos[0]); vrpn_buffer(&mptr, &mlen, Pos[1]); vrpn_buffer(&mptr, &mlen, Pos[2]); return buf; } vrpn_int32 vrpn_ForceDevice::decode_objectPosition(const char *buffer, vrpn_int32 len, vrpn_int32 *objNum, vrpn_float32 Pos[3]) { const char *mptr = buffer; if (len != (sizeof(vrpn_int32) + 3 * sizeof(vrpn_float32))) { fprintf(stderr, "vrpn_ForceDevice: object position message payload "); fprintf(stderr, "error\n (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32) + 3 * sizeof(vrpn_float32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); CHECK(vrpn_unbuffer(&mptr, &Pos[0])); CHECK(vrpn_unbuffer(&mptr, &Pos[1])); CHECK(vrpn_unbuffer(&mptr, &Pos[2])); return 0; } char *vrpn_ForceDevice::encode_objectOrientation(vrpn_int32 &len, const vrpn_int32 objNum, const vrpn_float32 axis[3], const vrpn_float32 angle) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32) + 4 * sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); vrpn_buffer(&mptr, &mlen, axis[0]); vrpn_buffer(&mptr, &mlen, axis[1]); vrpn_buffer(&mptr, &mlen, axis[2]); vrpn_buffer(&mptr, &mlen, angle); return buf; } vrpn_int32 vrpn_ForceDevice::decode_objectOrientation(const char *buffer, vrpn_int32 len, vrpn_int32 *objNum, vrpn_float32 axis[3], vrpn_float32 *angle) { const char *mptr = buffer; if (len != (sizeof(vrpn_int32) + 4 * sizeof(vrpn_float32))) { fprintf(stderr, "vrpn_ForceDevice: object orientation message payload "); fprintf(stderr, "error\n (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32) + 4 * sizeof(vrpn_float32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); CHECK(vrpn_unbuffer(&mptr, &axis[0])); CHECK(vrpn_unbuffer(&mptr, &axis[1])); CHECK(vrpn_unbuffer(&mptr, &axis[2])); CHECK(vrpn_unbuffer(&mptr, angle)); return 0; } char *vrpn_ForceDevice::encode_objectScale(vrpn_int32 &len, const vrpn_int32 objNum, const vrpn_float32 Scale[3]) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32) + 3 * sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); vrpn_buffer(&mptr, &mlen, Scale[0]); vrpn_buffer(&mptr, &mlen, Scale[1]); vrpn_buffer(&mptr, &mlen, Scale[2]); return buf; } vrpn_int32 vrpn_ForceDevice::decode_objectScale(const char *buffer, vrpn_int32 len, vrpn_int32 *objNum, vrpn_float32 Scale[3]) { const char *mptr = buffer; if (len != (sizeof(vrpn_int32) + 3 * sizeof(vrpn_float32))) { fprintf(stderr, "vrpn_ForceDevice: object scale message payload "); fprintf(stderr, "error\n (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32) + 3 * sizeof(vrpn_float32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); CHECK(vrpn_unbuffer(&mptr, &Scale[0])); CHECK(vrpn_unbuffer(&mptr, &Scale[1])); CHECK(vrpn_unbuffer(&mptr, &Scale[2])); return 0; } char *vrpn_ForceDevice::encode_removeObject(vrpn_int32 &len, const vrpn_int32 objNum) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); return buf; } vrpn_int32 vrpn_ForceDevice::decode_removeObject(const char *buffer, vrpn_int32 len, vrpn_int32 *objNum) { const char *mptr = buffer; if (len != sizeof(vrpn_int32)) { fprintf(stderr, "vrpn_ForceDevice: remove object message payload "); fprintf(stderr, "error\n (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); return 0; } char *vrpn_ForceDevice::encode_clearTrimesh(vrpn_int32 &len, const vrpn_int32 objNum) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); return buf; } vrpn_int32 vrpn_ForceDevice::decode_clearTrimesh(const char *buffer, vrpn_int32 len, vrpn_int32 *objNum) { const char *mptr = buffer; if (len != sizeof(vrpn_int32)) { fprintf(stderr, "vrpn_ForceDevice: clear TriMesh message payload "); fprintf(stderr, "error\n (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); return 0; } char *vrpn_ForceDevice::encode_moveToParent(vrpn_int32 &len, const vrpn_int32 objNum, const vrpn_int32 parentNum) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32) + sizeof(vrpn_int32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); vrpn_buffer(&mptr, &mlen, parentNum); return buf; } vrpn_int32 vrpn_ForceDevice::decode_moveToParent(const char *buffer, vrpn_int32 len, vrpn_int32 *objNum, vrpn_int32 *parentNum) { const char *mptr = buffer; if (len != (sizeof(vrpn_int32) + sizeof(vrpn_int32))) { fprintf(stderr, "vrpn_ForceDevice: move object to parent message payload "); fprintf(stderr, "error\n (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32) + sizeof(vrpn_int32))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); CHECK(vrpn_unbuffer(&mptr, parentNum)); return 0; } char *vrpn_ForceDevice::encode_setHapticOrigin(vrpn_int32 &len, const vrpn_float32 Pos[3], const vrpn_float32 axis[3], const vrpn_float32 angle) { int i; char *buf; char *mptr; vrpn_int32 mlen; len = 7 * sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; for (i = 0; i < 3; i++) vrpn_buffer(&mptr, &mlen, Pos[i]); for (i = 0; i < 3; i++) vrpn_buffer(&mptr, &mlen, axis[i]); vrpn_buffer(&mptr, &mlen, angle); return buf; } vrpn_int32 vrpn_ForceDevice::decode_setHapticOrigin(const char *buffer, vrpn_int32 len, vrpn_float32 Pos[3], vrpn_float32 axis[3], vrpn_float32 *angle) { int i; const char *mptr = buffer; if (len != 7 * sizeof(vrpn_int32)) { fprintf(stderr, "vrpn_ForceDevice: sethapticorigin message payload error\n"); fprintf(stderr, " (got %d, expected %lud)\n", len, static_cast<unsigned long>(7 * sizeof(vrpn_int32))); return -1; } for (i = 0; i < 3; i++) CHECK(vrpn_unbuffer(&mptr, &Pos[i])); for (i = 0; i < 3; i++) CHECK(vrpn_unbuffer(&mptr, &axis[i])); CHECK(vrpn_unbuffer(&mptr, angle)); return 0; } char *vrpn_ForceDevice::encode_setHapticScale(vrpn_int32 &len, const vrpn_float32 scale) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, scale); return buf; } vrpn_int32 vrpn_ForceDevice::decode_setHapticScale(const char *buffer, vrpn_int32 len, vrpn_float32 *scale) { const char *mptr = buffer; if (len != sizeof(vrpn_float32)) { fprintf(stderr, "vrpn_ForceDevice: sethapticscale message payload error\n"); fprintf(stderr, " (got %d, expected %lud)\n", len, static_cast<unsigned long>(7 * sizeof(vrpn_float32))); return -1; } CHECK(vrpn_unbuffer(&mptr, scale)); return 0; } char *vrpn_ForceDevice::encode_setSceneOrigin(vrpn_int32 &len, const vrpn_float32 Pos[3], const vrpn_float32 axis[3], const vrpn_float32 angle) { int i; char *buf; char *mptr; vrpn_int32 mlen; len = 7 * sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; for (i = 0; i < 3; i++) vrpn_buffer(&mptr, &mlen, Pos[i]); for (i = 0; i < 3; i++) vrpn_buffer(&mptr, &mlen, axis[i]); vrpn_buffer(&mptr, &mlen, angle); return buf; } vrpn_int32 vrpn_ForceDevice::decode_setSceneOrigin(const char *buffer, vrpn_int32 len, vrpn_float32 Pos[3], vrpn_float32 axis[3], vrpn_float32 *angle) { int i; const char *mptr = buffer; if (len != 7 * sizeof(vrpn_int32)) { fprintf(stderr, "vrpn_ForceDevice: setsceneorigin message payload error\n"); fprintf(stderr, " (got %d, expected %lud)\n", len, static_cast<unsigned long>(7 * sizeof(vrpn_int32))); return -1; } for (i = 0; i < 3; i++) CHECK(vrpn_unbuffer(&mptr, &Pos[i])); for (i = 0; i < 3; i++) CHECK(vrpn_unbuffer(&mptr, &axis[i])); CHECK(vrpn_unbuffer(&mptr, angle)); return 0; } char *vrpn_ForceDevice::encode_setObjectIsTouchable(vrpn_int32 &len, const vrpn_int32 objNum, const vrpn_bool IsTouchable) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32) + sizeof(vrpn_bool); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, objNum); vrpn_buffer(&mptr, &mlen, IsTouchable); return buf; } vrpn_int32 vrpn_ForceDevice::decode_setObjectIsTouchable(const char *buffer, vrpn_int32 len, vrpn_int32 *objNum, vrpn_bool *IsTouchable) { const char *mptr = buffer; if (len != (sizeof(vrpn_int32) + sizeof(vrpn_bool))) { fprintf(stderr, "vrpn_ForceDevice: set object is touchable message " "payload error\n"); fprintf( stderr, " (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32) + sizeof(vrpn_bool))); return -1; } CHECK(vrpn_unbuffer(&mptr, objNum)); CHECK(vrpn_unbuffer(&mptr, IsTouchable)); return 0; } // static char *vrpn_ForceDevice::encode_forcefield(vrpn_int32 &len, const vrpn_float32 origin[3], const vrpn_float32 force[3], const vrpn_float32 jacobian[3][3], const vrpn_float32 radius) { int i, j; char *buf; char *mptr; vrpn_int32 mlen; len = 16 * sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; for (i = 0; i < 3; i++) vrpn_buffer(&mptr, &mlen, origin[i]); for (i = 0; i < 3; i++) vrpn_buffer(&mptr, &mlen, force[i]); for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) vrpn_buffer(&mptr, &mlen, jacobian[i][j]); vrpn_buffer(&mptr, &mlen, radius); return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_forcefield( const char *buffer, const vrpn_int32 len, vrpn_float32 origin[3], vrpn_float32 force[3], vrpn_float32 jacobian[3][3], vrpn_float32 *radius) { int i, j; const char *mptr = buffer; if (len != 16 * sizeof(vrpn_float32)) { fprintf(stderr, "vrpn_ForceDevice: force field message payload error\n"); fprintf(stderr, " (got %d, expected %lud)\n", len, static_cast<unsigned long>(16 * sizeof(vrpn_float32))); return -1; } for (i = 0; i < 3; i++) CHECK(vrpn_unbuffer(&mptr, &(origin[i]))); for (i = 0; i < 3; i++) CHECK(vrpn_unbuffer(&mptr, &(force[i]))); for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) CHECK(vrpn_unbuffer(&mptr, &(jacobian[i][j]))); CHECK(vrpn_unbuffer(&mptr, radius)); return 0; } char *vrpn_ForceDevice::encode_error(vrpn_int32 &len, const vrpn_int32 error_code) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, error_code); return buf; } vrpn_int32 vrpn_ForceDevice::decode_error(const char *buffer, const vrpn_int32 len, vrpn_int32 *error_code) { const char *mptr = buffer; if (len != sizeof(vrpn_int32)) { fprintf(stderr, "vrpn_ForceDevice: error message payload error\n"); fprintf(stderr, " (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32))); return -1; } CHECK(vrpn_unbuffer(&mptr, error_code)); return 0; } void vrpn_ForceDevice::set_plane(vrpn_float32 *p) { for (int i = 0; i < 4; i++) { plane[i] = p[i]; } } void vrpn_ForceDevice::set_plane(vrpn_float32 a, vrpn_float32 b, vrpn_float32 c, vrpn_float32 d) { plane[0] = a; plane[1] = b; plane[2] = c; plane[3] = d; } void vrpn_ForceDevice::set_plane(vrpn_float32 *normal, vrpn_float32 d) { for (int i = 0; i < 3; i++) { plane[i] = normal[i]; } plane[3] = d; } void vrpn_ForceDevice::sendError(int error_code) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_error(len, error_code); if (d_connection->pack_message(len, timestamp, error_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // constraint message encode/decode methods // static char *vrpn_ForceDevice::encode_enableConstraint(vrpn_int32 &len, vrpn_int32 enable) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_int32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, enable); return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_enableConstraint(const char *buffer, const vrpn_int32 len, vrpn_int32 *enable) { const char *mptr = buffer; if (len != sizeof(vrpn_int32)) { fprintf(stderr, "vrpn_ForceDevice: " "enable constraint message payload error\n" " (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32))); return -1; } CHECK(vrpn_unbuffer(&mptr, enable)); return 0; } // static char *vrpn_ForceDevice::encode_setConstraintMode(vrpn_int32 &len, ConstraintGeometry mode) { char *buf; char *mptr; vrpn_int32 modeint; vrpn_int32 mlen; len = sizeof(vrpn_int32); mlen = len; buf = new char[len]; mptr = buf; switch (mode) { case NO_CONSTRAINT: modeint = 0; break; case POINT_CONSTRAINT: modeint = 1; break; case LINE_CONSTRAINT: modeint = 2; break; case PLANE_CONSTRAINT: modeint = 3; break; default: fprintf(stderr, "vrpn_ForceDevice: " "Unknown or illegal constraint mode.\n"); modeint = 0; break; } vrpn_buffer(&mptr, &mlen, modeint); return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_setConstraintMode(const char *buffer, const vrpn_int32 len, ConstraintGeometry *mode) { const char *mptr = buffer; vrpn_int32 modeint; if (len != sizeof(vrpn_int32)) { fprintf(stderr, "vrpn_ForceDevice: " "constraint mode payload error\n" " (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_int32))); return -1; } CHECK(vrpn_unbuffer(&mptr, &modeint)); switch (modeint) { case 0: *mode = NO_CONSTRAINT; break; case 1: *mode = POINT_CONSTRAINT; break; case 2: *mode = LINE_CONSTRAINT; break; case 3: *mode = PLANE_CONSTRAINT; break; default: fprintf(stderr, "vrpn_ForceDevice: " "Unknown or illegal constraint mode.\n"); *mode = NO_CONSTRAINT; return -1; } return 0; } // static char *vrpn_ForceDevice::encode_setConstraintPoint(vrpn_int32 &len, vrpn_float32 x, vrpn_float32 y, vrpn_float32 z) { return encodePoint(len, x, y, z); } // static vrpn_int32 vrpn_ForceDevice::decode_setConstraintPoint(const char *buffer, const vrpn_int32 len, vrpn_float32 *x, vrpn_float32 *y, vrpn_float32 *z) { return decodePoint(buffer, len, x, y, z); } // static char *vrpn_ForceDevice::encode_setConstraintLinePoint(vrpn_int32 &len, vrpn_float32 x, vrpn_float32 y, vrpn_float32 z) { return encodePoint(len, x, y, z); } // static vrpn_int32 vrpn_ForceDevice::decode_setConstraintLinePoint(const char *buffer, const vrpn_int32 len, vrpn_float32 *x, vrpn_float32 *y, vrpn_float32 *z) { return decodePoint(buffer, len, x, y, z); } // static char *vrpn_ForceDevice::encode_setConstraintLineDirection(vrpn_int32 &len, vrpn_float32 x, vrpn_float32 y, vrpn_float32 z) { return encodePoint(len, x, y, z); } // static vrpn_int32 vrpn_ForceDevice::decode_setConstraintLineDirection( const char *buffer, const vrpn_int32 len, vrpn_float32 *x, vrpn_float32 *y, vrpn_float32 *z) { return decodePoint(buffer, len, x, y, z); } // static char *vrpn_ForceDevice::encode_setConstraintPlanePoint(vrpn_int32 &len, vrpn_float32 x, vrpn_float32 y, vrpn_float32 z) { return encodePoint(len, x, y, z); } // static vrpn_int32 vrpn_ForceDevice::decode_setConstraintPlanePoint( const char *buffer, const vrpn_int32 len, vrpn_float32 *x, vrpn_float32 *y, vrpn_float32 *z) { return decodePoint(buffer, len, x, y, z); } // static char *vrpn_ForceDevice::encode_setConstraintPlaneNormal(vrpn_int32 &len, vrpn_float32 x, vrpn_float32 y, vrpn_float32 z) { return encodePoint(len, x, y, z); } // static vrpn_int32 vrpn_ForceDevice::decode_setConstraintPlaneNormal( const char *buffer, const vrpn_int32 len, vrpn_float32 *x, vrpn_float32 *y, vrpn_float32 *z) { return decodePoint(buffer, len, x, y, z); } // static char *vrpn_ForceDevice::encode_setConstraintKSpring(vrpn_int32 &len, vrpn_float32 k) { char *buf; char *mptr; vrpn_int32 mlen; len = sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, k); return buf; } // static vrpn_int32 vrpn_ForceDevice::decode_setConstraintKSpring(const char *buffer, const vrpn_int32 len, vrpn_float32 *k) { const char *mptr = buffer; if (len != sizeof(vrpn_float32)) { fprintf(stderr, "vrpn_ForceDevice: " "set constraint spring message payload error\n" " (got %d, expected %lud)\n", len, static_cast<unsigned long>(sizeof(vrpn_float32))); return -1; } CHECK(vrpn_unbuffer(&mptr, k)); return 0; } // // utility functions // // static char *vrpn_ForceDevice::encodePoint(vrpn_int32 &len, vrpn_float32 x, vrpn_float32 y, vrpn_float32 z) { char *buf; char *mptr; vrpn_int32 mlen; len = 3 * sizeof(vrpn_float32); mlen = len; buf = new char[len]; mptr = buf; vrpn_buffer(&mptr, &mlen, x); vrpn_buffer(&mptr, &mlen, y); vrpn_buffer(&mptr, &mlen, z); return buf; } // static vrpn_int32 vrpn_ForceDevice::decodePoint(const char *buffer, const vrpn_int32 len, vrpn_float32 *x, vrpn_float32 *y, vrpn_float32 *z) { const char *mptr = buffer; if (len != 3 * sizeof(vrpn_float32)) { fprintf(stderr, "vrpn_ForceDevice: " "decode point message payload error\n" " (got size %d, expected %lud)\n", len, static_cast<unsigned long>(3 * sizeof(vrpn_float32))); return -1; } CHECK(vrpn_unbuffer(&mptr, x)); CHECK(vrpn_unbuffer(&mptr, y)); CHECK(vrpn_unbuffer(&mptr, z)); return 0; } /* ******************** vrpn_ForceDevice_Remote ********************** */ vrpn_ForceDevice_Remote::vrpn_ForceDevice_Remote(const char *name, vrpn_Connection *cn) : vrpn_ForceDevice(name, cn) , d_conEnabled(0) , d_conMode(POINT_CONSTRAINT) { which_plane = 0; // Make sure that we have a valid connection if (d_connection == NULL) { fprintf(stderr, "vrpn_ForceDevice_Remote: No connection\n"); return; } // Register a handler for the change callback from this device. if (register_autodeleted_handler( force_message_id, handle_force_change_message, this, d_sender_id)) { fprintf(stderr, "vrpn_ForceDevice_Remote:can't register handler\n"); d_connection = NULL; } // Register a handler for the scp change callback from this device. if (register_autodeleted_handler(scp_message_id, handle_scp_change_message, this, d_sender_id)) { fprintf(stderr, "vrpn_ForceDevice_Remote:can't register handler\n"); d_connection = NULL; } // Register a handler for the error change callback from this device. if (register_autodeleted_handler( error_message_id, handle_error_change_message, this, d_sender_id)) { fprintf(stderr, "vrpn_ForceDevice_Remote:can't register handler\n"); d_connection = NULL; } // Find out what time it is and put this into the timestamp vrpn_gettimeofday(×tamp, NULL); } // virtual vrpn_ForceDevice_Remote::~vrpn_ForceDevice_Remote(void) {} void vrpn_ForceDevice_Remote::sendSurface(void) { // Encode the plane if there is a connection char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_plane(len, plane, SurfaceKspring, SurfaceKdamping, SurfaceFdynamic, SurfaceFstatic, which_plane, numRecCycles); if (d_connection->pack_message(len, timestamp, plane_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_LOW_LATENCY)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; msgbuf = encode_surface_effects( len, SurfaceKadhesionNormal, SurfaceKadhesionLateral, SurfaceTextureAmplitude, SurfaceTextureWavelength, SurfaceBuzzAmp, SurfaceBuzzFreq); if (d_connection->pack_message(len, timestamp, plane_effects_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_LOW_LATENCY)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } void vrpn_ForceDevice_Remote::startSurface(void) { // Encode the plane if there is a connection char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_plane(len, plane, SurfaceKspring, SurfaceKdamping, SurfaceFdynamic, SurfaceFstatic, which_plane, numRecCycles); if (d_connection->pack_message(len, timestamp, plane_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } void vrpn_ForceDevice_Remote::stopSurface(void) { // Encode the plane if there is a connection char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; set_plane(0, 0, 0, 0); if (d_connection) { msgbuf = encode_plane(len, plane, SurfaceKspring, SurfaceKdamping, SurfaceFdynamic, SurfaceFstatic, which_plane, numRecCycles); if (d_connection->pack_message(len, timestamp, plane_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } void vrpn_ForceDevice_Remote::setVertex(vrpn_int32 vertNum, vrpn_float32 x, vrpn_float32 y, vrpn_float32 z) { setObjectVertex(0, vertNum, x, y, z); } void vrpn_ForceDevice_Remote::setNormal(vrpn_int32 normNum, vrpn_float32 x, vrpn_float32 y, vrpn_float32 z) { setObjectNormal(0, normNum, x, y, z); } void vrpn_ForceDevice_Remote::setTriangle(vrpn_int32 triNum, vrpn_int32 vert0, vrpn_int32 vert1, vrpn_int32 vert2, vrpn_int32 norm0, vrpn_int32 norm1, vrpn_int32 norm2) { setObjectTriangle(0, triNum, vert0, vert1, vert2, norm0, norm1, norm2); } void vrpn_ForceDevice_Remote::removeTriangle(vrpn_int32 triNum) { removeObjectTriangle(0, triNum); } void vrpn_ForceDevice_Remote::updateTrimeshChanges() { updateObjectTrimeshChanges(0); } // set the trimesh's homogen transform matrix (in row major order) void vrpn_ForceDevice_Remote::setTrimeshTransform(vrpn_float32 homMatrix[16]) { setObjectTrimeshTransform(0, homMatrix); } // clear the triMesh if connection void vrpn_ForceDevice_Remote::clearTrimesh(void) { clearObjectTrimesh(0); } /** functions for multiple objects in the haptic scene * *************************************/ // Add an object to the haptic scene as root (parent -1 = default) or as child // (ParentNum =the number of the parent) void vrpn_ForceDevice_Remote::addObject(vrpn_int32 objNum, vrpn_int32 ParentNum /*=-1*/) { char *msgbuf; vrpn_int32 len; struct timeval current_time; if (objNum > m_NextAvailableObjectID) m_NextAvailableObjectID = objNum + 1; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_addObject(len, objNum, ParentNum); if (d_connection->pack_message(len, timestamp, addObject_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // Add an object next to the haptic scene as root void vrpn_ForceDevice_Remote::addObjectExScene(vrpn_int32 objNum) { char *msgbuf; vrpn_int32 len; struct timeval current_time; if (objNum > m_NextAvailableObjectID) m_NextAvailableObjectID = objNum + 1; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_addObjectExScene(len, objNum); if (d_connection->pack_message(len, timestamp, addObjectExScene_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // vertNum normNum and triNum start at 0 void vrpn_ForceDevice_Remote::setObjectVertex(vrpn_int32 objNum, vrpn_int32 vertNum, vrpn_float32 x, vrpn_float32 y, vrpn_float32 z) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_vertex(len, objNum, vertNum, x, y, z); if (d_connection->pack_message(len, timestamp, setVertex_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // NOTE: ghost doesn't take normals, // and normals still aren't implemented for Hcollide void vrpn_ForceDevice_Remote::setObjectNormal(vrpn_int32 objNum, vrpn_int32 normNum, vrpn_float32 x, vrpn_float32 y, vrpn_float32 z) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_normal(len, objNum, normNum, x, y, z); if (d_connection->pack_message(len, timestamp, setNormal_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } void vrpn_ForceDevice_Remote::setObjectTriangle( vrpn_int32 objNum, vrpn_int32 triNum, vrpn_int32 vert0, vrpn_int32 vert1, vrpn_int32 vert2, vrpn_int32 norm0 /*=-1*/, vrpn_int32 norm1 /*=-1*/, vrpn_int32 norm2 /*=-1*/) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_triangle(len, objNum, triNum, vert0, vert1, vert2, norm0, norm1, norm2); if (d_connection->pack_message(len, timestamp, setTriangle_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } void vrpn_ForceDevice_Remote::removeObjectTriangle(vrpn_int32 objNum, vrpn_int32 triNum) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_removeTriangle(len, objNum, triNum); if (d_connection->pack_message(len, timestamp, removeTriangle_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // should be called to incorporate the above changes into the // displayed trimesh void vrpn_ForceDevice_Remote::updateObjectTrimeshChanges(vrpn_int32 objNum) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_updateTrimeshChanges(len, objNum, SurfaceKspring, SurfaceKdamping, SurfaceFstatic, SurfaceFdynamic); if (d_connection->pack_message( len, timestamp, updateTrimeshChanges_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // set the trimesh's homogen transform matrix (in row major order) void vrpn_ForceDevice_Remote::setObjectTrimeshTransform( vrpn_int32 objNum, vrpn_float32 homMatrix[16]) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_trimeshTransform(len, objNum, homMatrix); if (d_connection->pack_message(len, timestamp, transformTrimesh_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // set position of an object void vrpn_ForceDevice_Remote::setObjectPosition(vrpn_int32 objNum, vrpn_float32 Pos[3]) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_objectPosition(len, objNum, Pos); if (d_connection->pack_message( len, timestamp, setObjectPosition_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // set orientation of an object void vrpn_ForceDevice_Remote::setObjectOrientation(vrpn_int32 objNum, vrpn_float32 axis[3], vrpn_float32 angle) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_objectOrientation(len, objNum, axis, angle); if (d_connection->pack_message( len, timestamp, setObjectOrientation_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // set Scale of an object void vrpn_ForceDevice_Remote::setObjectScale(vrpn_int32 objNum, vrpn_float32 Scale[3]) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_objectScale(len, objNum, Scale); if (d_connection->pack_message(len, timestamp, setObjectScale_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // remove an object from the scene void vrpn_ForceDevice_Remote::removeObject(vrpn_int32 objNum) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_removeObject(len, objNum); if (d_connection->pack_message(len, timestamp, removeObject_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } void vrpn_ForceDevice_Remote::clearObjectTrimesh(vrpn_int32 objNum) { char *msgbuf = NULL; vrpn_int32 len = 0; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_clearTrimesh(len, objNum); if (d_connection->pack_message(len, timestamp, clearTrimesh_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } /** Functions to organize the scene * **********************************************************/ // Change The parent of an object void vrpn_ForceDevice_Remote::moveToParent(vrpn_int32 objNum, vrpn_int32 ParentNum) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_moveToParent(len, objNum, ParentNum); if (d_connection->pack_message(len, timestamp, moveToParent_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // Set the Origin of the haptic scene void vrpn_ForceDevice_Remote::setHapticOrigin(vrpn_float32 Pos[3], vrpn_float32 axis[3], vrpn_float32 angle) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_setHapticOrigin(len, Pos, axis, angle); if (d_connection->pack_message(len, timestamp, setHapticOrigin_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // Set the scale of the haptic scene void vrpn_ForceDevice_Remote::setHapticScale(vrpn_float32 Scale) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_setHapticScale(len, Scale); if (d_connection->pack_message(len, timestamp, setHapticScale_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } void vrpn_ForceDevice_Remote::setSceneOrigin(vrpn_float32 Pos[3], vrpn_float32 axis[3], vrpn_float32 angle) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_setSceneOrigin(len, Pos, axis, angle); if (d_connection->pack_message(len, timestamp, setSceneOrigin_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // get new ID, use only if wish to use vrpn ids and do not want to manage them // yourself: ids need to be unique vrpn_int32 vrpn_ForceDevice_Remote::getNewObjectID() { return m_NextAvailableObjectID++; } // make an object touchable or not void vrpn_ForceDevice_Remote::setObjectIsTouchable( vrpn_int32 objNum, vrpn_bool IsTouchable /*=true*/) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_setObjectIsTouchable(len, objNum, IsTouchable); if (d_connection->pack_message( len, timestamp, setObjectIsTouchable_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // the next time we send a trimesh we will use the following type void vrpn_ForceDevice_Remote::useHcollide(void) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_setTrimeshType(len, -1, HCOLLIDE); if (d_connection->pack_message(len, timestamp, setTrimeshType_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } void vrpn_ForceDevice_Remote::useGhost(void) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_setTrimeshType(len, -1, GHOST); if (d_connection->pack_message(len, timestamp, setTrimeshType_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // ajout ONDIM void vrpn_ForceDevice_Remote::startEffect(void) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_custom_effect(len, customEffectId, customEffectParams, nbCustomEffectParams); if (d_connection->pack_message(len, timestamp, custom_effect_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } void vrpn_ForceDevice_Remote::stopEffect(void) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; setCustomEffect(-1, NULL, 0); if (d_connection) { msgbuf = encode_custom_effect(len, customEffectId, customEffectParams, nbCustomEffectParams); if (d_connection->pack_message(len, timestamp, custom_effect_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // fin ajout ONDIM // // constraint methods // #ifndef FD_SPRINGS_AS_FIELDS #if 0 void vrpn_ForceDevice_Remote::enableConstraint (vrpn_int32 enable) { } void vrpn_ForceDevice_Remote::setConstraintMode (ConstraintGeometry mode) { } void vrpn_ForceDevice_Remote::setConstraintPoint } void vrpn_ForceDevice_Remote::setConstraintLinePoint } void vrpn_ForceDevice_Remote::setConstraintLineDirection } void vrpn_ForceDevice_Remote::setConstraintPlanePoint } void vrpn_ForceDevice_Remote::setConstraintPlaneNormal } void vrpn_ForceDevice_Remote::setConstraintKSpring (vrpn_float32 k) { } #endif // 0 #else void vrpn_ForceDevice_Remote::enableConstraint(vrpn_int32 enable) { if (enable == d_conEnabled) return; d_conEnabled = enable; switch (d_conEnabled) { case 0: stopForceField(); break; case 1: constraintToForceField(); sendForceField(); break; default: fprintf(stderr, "vrpn_ForceDevice_Remote::enableConstraint: " "Illegal value of enable (%d).\n", enable); break; } } void vrpn_ForceDevice_Remote::setConstraintMode(ConstraintGeometry mode) { d_conMode = mode; constraintToForceField(); if (d_conEnabled) { sendForceField(); } } void vrpn_ForceDevice_Remote::setConstraintPoint(vrpn_float32 point[3]) { d_conPoint[0] = point[0]; d_conPoint[1] = point[1]; d_conPoint[2] = point[2]; constraintToForceField(); if (d_conEnabled) { sendForceField(); } } void vrpn_ForceDevice_Remote::setConstraintLinePoint(vrpn_float32 point[3]) { d_conLinePoint[0] = point[0]; d_conLinePoint[1] = point[1]; d_conLinePoint[2] = point[2]; constraintToForceField(); if (d_conEnabled) { sendForceField(); } } void vrpn_ForceDevice_Remote::setConstraintLineDirection( vrpn_float32 direction[3]) { d_conLineDirection[0] = direction[0]; d_conLineDirection[1] = direction[1]; d_conLineDirection[2] = direction[2]; constraintToForceField(); if (d_conEnabled) { sendForceField(); } } void vrpn_ForceDevice_Remote::setConstraintPlanePoint(vrpn_float32 point[3]) { d_conPlanePoint[0] = point[0]; d_conPlanePoint[1] = point[1]; d_conPlanePoint[2] = point[2]; constraintToForceField(); if (d_conEnabled) { sendForceField(); } } void vrpn_ForceDevice_Remote::setConstraintPlaneNormal(vrpn_float32 normal[3]) { d_conPlaneNormal[0] = normal[0]; d_conPlaneNormal[1] = normal[1]; d_conPlaneNormal[2] = normal[2]; constraintToForceField(); if (d_conEnabled) { sendForceField(); } } void vrpn_ForceDevice_Remote::setConstraintKSpring(vrpn_float32 k) { d_conKSpring = k; constraintToForceField(); if (d_conEnabled) { sendForceField(); } } #endif // FD_SPRINGS_AS_FIELDS void vrpn_ForceDevice_Remote::sendForceField(void) { sendForceField(ff_origin, ff_force, ff_jacobian, ff_radius); } void vrpn_ForceDevice_Remote::sendForceField(vrpn_float32 origin[3], vrpn_float32 force[3], vrpn_float32 jacobian[3][3], vrpn_float32 radius) { char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_forcefield(len, origin, force, jacobian, radius); if (d_connection->pack_message(len, timestamp, forcefield_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_LOW_LATENCY)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } // same as sendForceField but sets force to 0 and sends RELIABLY void vrpn_ForceDevice_Remote::stopForceField(void) { vrpn_float32 origin[3] = {0, 0, 0}; vrpn_float32 force[3] = {0, 0, 0}; vrpn_float32 jacobian[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; vrpn_float32 radius = 0; char *msgbuf; vrpn_int32 len; struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; if (d_connection) { msgbuf = encode_forcefield(len, origin, force, jacobian, radius); if (d_connection->pack_message(len, timestamp, forcefield_message_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "Phantom: cannot write message: tossing\n"); } delete[] msgbuf; } } void vrpn_ForceDevice_Remote::mainloop() { if (d_connection) { d_connection->mainloop(); } client_mainloop(); } int vrpn_ForceDevice_Remote::handle_force_change_message(void *userdata, vrpn_HANDLERPARAM p) { vrpn_ForceDevice_Remote *me = (vrpn_ForceDevice_Remote *)userdata; vrpn_FORCECB tp; tp.msg_time = p.msg_time; decode_force(p.buffer, p.payload_len, tp.force); me->d_change_list.call_handlers(tp); return 0; } int vrpn_ForceDevice_Remote::handle_scp_change_message(void *userdata, vrpn_HANDLERPARAM p) { vrpn_ForceDevice_Remote *me = (vrpn_ForceDevice_Remote *)userdata; vrpn_FORCESCPCB tp; tp.msg_time = p.msg_time; decode_scp(p.buffer, p.payload_len, tp.pos, tp.quat); me->d_scp_change_list.call_handlers(tp); return 0; } int vrpn_ForceDevice_Remote::handle_error_change_message(void *userdata, vrpn_HANDLERPARAM p) { vrpn_ForceDevice_Remote *me = (vrpn_ForceDevice_Remote *)userdata; vrpn_FORCEERRORCB tp; if (p.payload_len != sizeof(vrpn_int32)) { fprintf(stderr, "vrpn_ForceDevice: error message payload" " error\n(got %d, expected %lud)\n", p.payload_len, static_cast<unsigned long>(sizeof(vrpn_int32))); return -1; } tp.msg_time = p.msg_time; decode_error(p.buffer, p.payload_len, &(tp.error_code)); me->d_error_change_list.call_handlers(tp); return 0; } void vrpn_ForceDevice_Remote::send(const char *msgbuf, vrpn_int32 len, vrpn_int32 type) { struct timeval now; vrpn_gettimeofday(&now, NULL); timestamp.tv_sec = now.tv_sec; timestamp.tv_usec = now.tv_usec; if (d_connection) { if (d_connection->pack_message(len, now, type, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "vrpn_ForceDevice_Remote::send: Can't pack message.\n"); } } // HP compiler won't let you delete a const argument. delete[](char *)msgbuf; } #ifdef FD_SPRINGS_AS_FIELDS void vrpn_ForceDevice_Remote::constraintToForceField(void) { vrpn_float32 c[9]; // scratch matrix int i, j; // quatlib wants 64-bit reals; the forcefield code wants 32-bit // reals. We do most of our math in 64 bits, then copy into 32 // for output to force field. const float largeRadius = 100.0f; // infinity switch (d_conMode) { case NO_CONSTRAINT: break; case POINT_CONSTRAINT: setFF_Origin(d_conPoint); setFF_Force(0.0f, 0.0f, 0.0f); setFF_Jacobian(-d_conKSpring, 0.0f, 0.0f, 0.0f, -d_conKSpring, 0.0f, 0.0f, 0.0f, -d_conKSpring); setFF_Radius(largeRadius); break; case LINE_CONSTRAINT: { setFF_Origin(d_conLinePoint); setFF_Force(0.0f, 0.0f, 0.0f); // Paul Grayson (pdg@mit.edu) points out that rotating the Jacobian // won't work and we should use something simpler here. // Unfortunately, it's because of the apparent difficulty of this // case that we'd tried rotating a Jacobian in the first place. // Time to hit the books again looking for something that'll work. //------------------------------------------------------------------ // We want to generate a force that is in the opposite direction // of the offset between where the pen is and where the line is // defined to be. Because we are going to multiply the jacobian by // this offset vector, we want it to hold values that produce a // force that is in the direction of -OFFSET, but we want the // force to be scaled by the amount by which OFFSET is perpendicular // to the line direction (it should be zero along the line). So, // along the line direction it should always evaluate to (0,0,0) // independent of OFFSET, and perpendicular to this it should // always be OFFSET in length in direction -OFFSET, // which is just -OFFSET, which makes the matrix act like // -1 scaled by the spring constant. This means that we want a // matrix with Eigenvalues (-1, -1, 0) whose 0 Eigenvector lies // along the line direction. We get this by compositing a matrix // that rotates this vector to lie along Z, then applying the diagonal // (-1, -1, 0) matrix, then a matrix that rotates Z back to the // line direction. Remember to scale all of this by the spring // constant; // we do this during the diagonal matrix construction. // Normalize the direction to avoid having its length scale the force q_vec_type norm_line_dir; vrpn_float64 norm_len = sqrt((d_conLineDirection[0] * d_conLineDirection[0]) + (d_conLineDirection[1] * d_conLineDirection[1]) + (d_conLineDirection[2] * d_conLineDirection[2])); if (norm_len == 0) { norm_len = 1; } for (i = 0; i < 3; i++) { norm_line_dir[i] = d_conLineDirection[i] / norm_len; } // Construct the rotation from the normalized direction to +Z // and the rotation back. q_vec_type z_dir = {0, 0, 1}; q_type q_forward; q_matrix_type forward; q_type q_reverse; q_matrix_type reverse; q_from_two_vecs(q_forward, norm_line_dir, z_dir); q_to_row_matrix(forward, q_forward); q_invert(q_reverse, q_forward); q_to_row_matrix(reverse, q_reverse); // Construct the (-d_conKSpring, -d_conKSpring, 0) matrix and catenate // the // matrices to form the final jacobian. q_matrix_type diagonal, temp, jacobian; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { if ((i == j) && (i < 2)) { diagonal[i][j] = -d_conKSpring; } else { diagonal[i][j] = 0.0; } } } q_matrix_mult(temp, diagonal, forward); q_matrix_mult(jacobian, reverse, temp); // Grab the upper-left 3x3 portion of the jacobian and put it into // the coefficients. for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { c[i + j * 3] = (vrpn_float32)jacobian[i][j]; } } setFF_Jacobian(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8]); setFF_Radius(largeRadius); }; break; case PLANE_CONSTRAINT: { setFF_Origin(d_conPlanePoint); setFF_Force(0.0f, 0.0f, 0.0f); // Normalize the direction to avoid having its length scale the force vrpn_float64 norm_plane_dir[3]; vrpn_float64 norm_len = sqrt((d_conPlaneNormal[0] * d_conPlaneNormal[0]) + (d_conPlaneNormal[1] * d_conPlaneNormal[1]) + (d_conPlaneNormal[2] * d_conPlaneNormal[2])); if (norm_len == 0) { norm_len = 1; } for (i = 0; i < 3; i++) { norm_plane_dir[i] = d_conPlaneNormal[i] / norm_len; } // Paul Grayson (pdg@mit.edu) points out that rotating the Jacobian // won't work and we should use something simpler here. The below // is his code. for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) c[i + j * 3] = (vrpn_float32)( -d_conKSpring * norm_plane_dir[i] * norm_plane_dir[j]); setFF_Jacobian(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8]); setFF_Radius(largeRadius); }; break; } } #endif // FD_SPRINGS_AS_FIELDS