UnityMol  0.9.6-875
UnityMol viewer / In developement
VRPNManager.cs
Go to the documentation of this file.
1 using UnityEngine;
2 using System;
3 using System.Collections;
4 using System.Collections.Generic;
5 using System.Linq;
6 using System.Runtime.InteropServices;
7 using System.Reflection;
8 using UI;
9 
10 namespace VRPN
11 {
12  // The set of tool types.
13  // An interactor is used to pull atoms during interactive molecular dynamics simulations.
14  // When the interactor holds a force feedback connection, the tool magnetized by atoms.
15  // When pulling an atom, the force feedback provides an insight into the applied force amplitude.
16  public enum VRPNToolType {
17  INTERACTOR,
18  EXPLORER,
19  }
20 
21  // A set of VRPN connection references for a single tool.
23  public System.IntPtr force_feedback;
24  public System.IntPtr tracker;
25  public System.IntPtr buttons;
26 
27  public VRPNToolConnections(System.IntPtr force_feedback = new IntPtr(), System.IntPtr buttons = new IntPtr(), System.IntPtr tracker = new IntPtr()) {
29  this.tracker = tracker;
30  this.buttons = buttons;
31  }
32  }
33 
34  // A tool instance data, that is its type and the scene game object and a few more.
37  // The game object of the tracker.
38  public GameObject go;
39  // The game object of the haptic workspace.
40  public GameObject workspaceGo;
41  // The last workspace position in the scene. Used for clutching.
42  public Vector3 last_workspace_position;
43  // The last tracker position in the scene. Used for clutching.
44  public Vector3 last_tracker_position;
45  // True when the clutching feature is on.
46  public bool clutch;
47  // The game object of the atom highlight.
48  public GameObject selection_sphere;
49  // A reference to the closest atom.
51  // True activates the closest atom search. Set to false when pulling an atom.
52  public bool get_closest_atom;
53  }
54 
55  // Manages the VRPN connections and tools instantiation.
56  // Associates a set of connections to each tool.
57  // Provides the public API other systems should interface with.
58  //
59  // When a VRPN device is instanciated, it has to be polled one time for the connection to be effective.
60  // Otherwise, functions vrpn_c_[button|tracker|...]_is_connected() return false.
61  public class VRPNManager {
62 
63  // The function delegates used as VRPN callbacks, one for each kind of VRPN device.
67 
68  // The list of instanciated tools.
69  List<VRPNToolInstance> tools = new List<VRPNToolInstance>();
70  // The list of VRPN connection structures. Correspond one-to-one to tool instances.
71  List<VRPNToolConnections> connections = new List<VRPNToolConnections>();
72 
73  // Warning: Side Effect Heavy
74  // We cannot pass the tool index as a parameter due to VRPN callbacks signature.
75  int current_tool_index = 0;
76 
77  // Callback function called by VRPN when receiving tracker reports for an interactor tool.
78  public void interactorTrackerCallback(uint sensor, System.IntPtr pos, System.IntPtr quat)
79  {
80  VRPNToolInstance tool = tools[current_tool_index];
81  GameObject go = tool.go;
82 
83  double[] managedArray = new double[3];
84  double[] quaternionArray = new double[4];
85  Marshal.Copy(pos, managedArray, 0, 3);
86  Marshal.Copy(quat, quaternionArray, 0, 4);
87 
88  float factor = 20f;
89  float clutchingFactor = 6f;
90 
91  // Z-axis is inverted to reflect the phantom omni position correctly.
92  Vector3 scaledTrackerPositionVector = new Vector3((float)managedArray[0] * factor, (float)managedArray[1] * factor, -(float)managedArray[2] * factor);
93 
94  if (tool.clutch) {
95  tool.workspaceGo.transform.localPosition = tool.last_workspace_position + (tool.last_tracker_position - scaledTrackerPositionVector) * clutchingFactor;
96  }
97  else {
98  tool.go.transform.localPosition = scaledTrackerPositionVector;
99  tool.go.transform.localRotation = new Quaternion(-(float)quaternionArray[0], -(float)quaternionArray[1], (float)quaternionArray[2], (float)quaternionArray[3]);
100 
101  if (UIData.atomtype != UIData.AtomType.optihb && UIData.atomtype != UIData.AtomType.particleball && tool.get_closest_atom) {
103  tool.closest_atom = atomManager.getClosestAtomGameObject(go.transform.position);
104 
105  tool.selection_sphere.transform.parent = tool.closest_atom.go.transform;
106  tool.selection_sphere.transform.localPosition = Vector3.zero;
107 
108  tools[current_tool_index] = tool;
109  }
110  }
111  }
112 
113  // Callback function called by VRPN when receiving button reports for an interactor tool.
114  // Asserts the presence of two buttons numbered 0 and 1.
115  public void interactorButtonCallback(Int32 button, Int32 state)
116  {
117  VRPNToolInstance tool = tools[current_tool_index];
118 
121 
122  // The dark gray button of the phantom omni is pressed.
123  // When an interactive simulation is running, this has the effect to apply a force on the closest atom.
124  if (button == 0 && state == 1) {
125  tool.get_closest_atom = false;
126 
127  // Pull the closest atom.
128  Vector3 force = tool.go.transform.position - tool.closest_atom.go.transform.position;
129  artemis.send_forces(1, new int[1] {tool.closest_atom.pdbIndex}, new float[3] {force.x, force.y, force.z});
130 
131  tools[current_tool_index] = tool;
132  }
133 
134  if (button == 0 && state == 0) {
135  // Reset the force on the closest atom.
136  artemis.send_forces(1, new int[1] {0}, new float[3] {0f, 0f, 0f});
137 
138  tool.get_closest_atom = true;
139  tools[current_tool_index] = tool;
140  }
141  }
142 
143  // The light gray button of the phantom omni is pressed.
144  // This allows the workspace to be moved in space relative to the camera, a kind of clutching feature.
145  if (button == 1 && state == 1) {
146  tool.last_workspace_position = tool.workspaceGo.transform.localPosition;
147  tool.last_tracker_position = tool.go.transform.localPosition;
148  tool.clutch = true;
149  tools[current_tool_index] = tool;
150  }
151 
152  // The light gray button of the phantom omni is released.
153  // Disable the clutching. Allows the tool to move freely again.
154  if (button == 1 && state == 0) {
155  tool.clutch = false;
156  tools[current_tool_index] = tool;
157  }
158  }
159 
161  {
162  Debug.Log("----------");
163  Debug.Log(report.tv_sec);
164  Debug.Log(report.tv_usec);
165  Debug.Log(report.num_channel);
166  Debug.Log("----------Tran");
167  Debug.Log(report.channel[0]);
168  Debug.Log(report.channel[1]);
169  Debug.Log(report.channel[2]);
170  Debug.Log("----------Rot");
171  Debug.Log(report.channel[3]);
172  Debug.Log(report.channel[4]);
173  Debug.Log(report.channel[5]);
174  }
175 
176  public VRPNManager() {
177  MethodInfo minfo = typeof(VRPNManager).GetMethod("interactorTrackerCallback");
178  interactorTrackerDelegate = (VRPN.Wrapper.TrackerCallbackDelegate) Delegate.CreateDelegate(typeof(VRPN.Wrapper.TrackerCallbackDelegate), this, minfo, false);
179 
180  MethodInfo minfo2 = typeof(VRPNManager).GetMethod("interactorButtonCallback");
181  interactorButtonDelegate = (VRPN.Wrapper.ButtonCallbackDelegate) Delegate.CreateDelegate(typeof(VRPN.Wrapper.ButtonCallbackDelegate), this, minfo2, false);
182 
183  MethodInfo minfo3 = typeof(VRPNManager).GetMethod("explorerAnalogCallback");
184  explorerAnalogDelegate = (VRPN.Wrapper.AnalogCallbackDelegate) Delegate.CreateDelegate(typeof(VRPN.Wrapper.AnalogCallbackDelegate), this, minfo3, false);
185  }
186 
187  /**************
188  * Public API *
189  **************/
190 
191  // Clear all instantiated tools.
192  // This has the consequence to correctly close VRPN connections.
193  public void clearTools() {
194  int count = connections.Count;
195  for (int i = count-1; i >= 0 ; i--) {
196  RemoveTool(i);
197  }
198  }
199 
200  // Performs VRPN connections polling for every tool.
201  public void DeviceLoop() {
203 
204  int count = connections.Count;
205 
206  for (int i = 0; i < count; i++) {
207  current_tool_index = i;
208 
209  c = connections[i];
210 
211  if ((c.tracker != System.IntPtr.Zero) && (VRPN.Wrapper.vrpn_c_tracker_is_connected(c.tracker))) {
213  }
214 
215  if ((c.buttons != System.IntPtr.Zero) && (VRPN.Wrapper.vrpn_c_button_is_connected(c.buttons))) {
217  }
218  }
219  }
220 
221  // Allocates a VRPN tool and returns a index related to it.
222  // Returns true if the process ended as expected.
223  public int InstantiateTool(VRPNToolType tool_type) {
224  Debug.Log("VRPN: Adding tool of type " + tool_type.ToString());
225 
226  VRPNToolInstance instance = new VRPNToolInstance();
227  instance.type = tool_type;
228  instance.get_closest_atom = true;
229 
231  instance.closest_atom = atomManager.getClosestAtomGameObject(Vector3.zero);
232 
233  GameObject go = GameObject.Instantiate(Resources.Load("VRPN/VRPNPicker", typeof(GameObject)), Vector3.zero, Quaternion.identity) as GameObject;
234 
235  GameObject workspaceGo = GameObject.Instantiate(Resources.Load("VRPN/VRPN Interactor Grid") as GameObject);
236 
237  workspaceGo.transform.parent = Camera.main.transform;
238  workspaceGo.transform.localPosition = Vector3.zero;
239  workspaceGo.transform.localRotation = Quaternion.identity;
240  workspaceGo.transform.Translate(new Vector3(0f, 0f, 30f));
241 
242  go.transform.parent = workspaceGo.transform;
243  go.transform.localPosition = Vector3.zero;
244  go.transform.localRotation = Quaternion.identity;
245 
246  instance.go = go;
247  instance.workspaceGo = workspaceGo;
248 
249  // Instantiate a transparent selection sphere that is disabled until use.
250  GameObject selection_sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
251  selection_sphere.transform.localScale = Vector3.one * 2f;
252 
253  Shader s = Shader.Find("Transparent/Diffuse");
254  selection_sphere.GetComponent<Renderer>().material.shader = s;
255  Color c = Color.yellow;
256  c.a = 0.5f;
257  selection_sphere.GetComponent<Renderer>().material.color = c;
258 
259  instance.selection_sphere = selection_sphere;
260 
261  this.tools.Add(instance);
262 
263  VRPNToolConnections connections_instance = new VRPNToolConnections();
264  this.connections.Add(connections_instance);
265 
266  Debug.Log("VRPN: Tool was added");
267  return this.tools.Count() - 1;
268  }
269 
270  // Deallocates an instantiated tool based on its index.
271  // Returns true if the process ended as expected.
272  public bool RemoveTool(int tool_instance_index)
273  {
274  Debug.Log("VRPN: Attempting to remove tool number " + tool_instance_index);
275 
276  // Retrieve VRPN connections references and close them.
277  // This avoids dangling pointers to VRPN objects.
279 
280  try {
281  c = connections[tool_instance_index];
282  }
283  catch (ArgumentOutOfRangeException) {
284  return false;
285  }
286 
287  if (c.force_feedback != System.IntPtr.Zero) {
289  c.force_feedback = System.IntPtr.Zero;
290  }
291 
292  if (c.tracker != System.IntPtr.Zero) {
294  c.tracker = System.IntPtr.Zero;
295  }
296 
297  if (c.buttons != System.IntPtr.Zero) {
299  c.buttons = System.IntPtr.Zero;
300  }
301 
302  // Reset VRPN connections pointers.
303  this.connections[tool_instance_index] = c;
304 
305  // Completely delete the tool from the manager's memory.
306  // Also, destroy associated game objects.
307  try {
308  GameObject go;
309  GameObject workspaceGo;
310  GameObject sphereGo;
311 
312  go = this.tools[tool_instance_index].go;
313  workspaceGo = this.tools[tool_instance_index].workspaceGo;
314  sphereGo = this.tools[tool_instance_index].selection_sphere;
315 
316  GameObject.Destroy(go);
317  GameObject.Destroy(workspaceGo);
318  GameObject.Destroy(sphereGo);
319 
320  this.tools.RemoveAt(tool_instance_index);
321  this.connections.RemoveAt(tool_instance_index);
322  }
323  catch(ArgumentOutOfRangeException) {
324  return false;
325  }
326 
327  Debug.Log("VRPN: Removed tool correctly.");
328  return true;
329  }
330 
331  // Connects a tool to a VRPN Force Feedback server based on the server address.
332  // Returns true if a VRPN Connection was actually created, false otherwise.
333  public bool ConnectToolToForceFeedback(int tool_instance_index, string vrpn_device) {
334  VRPNToolConnections connections_instance;
335  try {
336  connections_instance = this.connections[tool_instance_index];
337  }
338  catch (Exception) {
339  return false;
340  }
341 
342  System.IntPtr ff_connection = VRPN.Wrapper.vrpn_c_open_force_feedback(vrpn_device);
343 
344  // Wait a bit for the connection instantiation.
345  System.Threading.Thread.Sleep(50);
346 
347  // Check if the target machine is effectively reached.
348  // Despite this precaution, it does not mean there is effectively a VRPN server on the target machine.
349  if (!VRPN.Wrapper.vrpn_c_force_feedback_doing_okay(ff_connection)) {
350  Debug.LogWarning("Button instance got closed due to a mistaking server address.");
352  return false;
353  }
354 
355  VRPN.Wrapper.vrpn_c_force_feedback_set_force(ff_connection, 0f, 0f, 0f);
356 
357  connections_instance.force_feedback = ff_connection;
358 
359  this.connections[tool_instance_index] = connections_instance;
360 
361  return true;
362  }
363 
364  // Connects a tool to a VRPN Tracker server based on the server address.
365  // Returns true if a VRPN Connection was actually created, false otherwise.
366  public bool ConnectToolToTracker(int tool_instance_index, string vrpn_device) {
367  VRPNToolConnections connections_instance;
368  try {
369  connections_instance = this.connections[tool_instance_index];
370  }
371  catch (Exception) {
372  return false;
373  }
374 
375  System.IntPtr tracker_connection = VRPN.Wrapper.vrpn_c_open_tracker(vrpn_device, interactorTrackerDelegate);
376 
377  // Wait a bit for the connection instantiation.
378  System.Threading.Thread.Sleep(50);
379 
380  // Check if the target machine is effectively reached.
381  // Despite this precaution, it does not mean there is effectively a VRPN server on the target machine.
382  if (!VRPN.Wrapper.vrpn_c_tracker_doing_okay(tracker_connection)) {
383  Debug.LogWarning("Tracker instance got closed due to a mistaking server address.");
384  VRPN.Wrapper.vrpn_c_close_tracker(tracker_connection);
385  return false;
386  }
387 
388  // To effectively initiate a connection, a VRPN device has to be polled at least one time.
389  // When an ExecutionEngine Exception occurs, the server address is incorrect.
390  VRPN.Wrapper.vrpn_c_poll_tracker(tracker_connection);
391 
392  connections_instance.tracker = tracker_connection;
393 
394  this.connections[tool_instance_index] = connections_instance;
395 
396  return true;
397  }
398 
399  // Connects a tool to a VRPN Buttons server based on the server address.
400  // Returns true if a VRPN Connection was actually created, false otherwise.
401  public bool ConnectToolToButtons(int tool_instance_index, string vrpn_device) {
402  VRPNToolConnections connections_instance;
403  try {
404  connections_instance = this.connections[tool_instance_index];
405  }
406  catch (Exception) {
407  return false;
408  }
409 
410  System.IntPtr button_connection = VRPN.Wrapper.vrpn_c_open_button(vrpn_device, interactorButtonDelegate);
411 
412  // Wait a bit for the connection instantiation.
413  System.Threading.Thread.Sleep(50);
414 
415  // Check if the target machine is effectively reached.
416  // Despite this precaution, it does not mean there is effectively a VRPN server on the target machine.
417  if (!VRPN.Wrapper.vrpn_c_button_doing_okay(button_connection)) {
418  Debug.LogWarning("Button instance got closed due to a mistaking server address.");
419  VRPN.Wrapper.vrpn_c_close_button(button_connection);
420  return false;
421  }
422 
423  // To effectively initiate a connection, a VRPN device has to be polled at least one time.
424  // When an ExecutionEngine Exception occurs, the server address is incorrect.
425  VRPN.Wrapper.vrpn_c_poll_button(button_connection);
426 
427  connections_instance.buttons = button_connection;
428 
429  this.connections[tool_instance_index] = connections_instance;
430 
431  return true;
432  }
433 
434  // Disconnects a tool from a VRPN Force Feedback server based on the tool index.
435  // Returns true if the VRPN Connection was actually destroyed, false otherwise.
436  public bool DisconnectToolFromForceFeedback(int tool_instance_index) {
437  VRPNToolConnections connections_instance;
438  try {
439  connections_instance = this.connections[tool_instance_index];
440  }
441  catch (Exception) {
442  return false;
443  }
444 
446 
447  if (VRPN.Wrapper.vrpn_c_close_force_feedback(connections_instance.force_feedback)) {
448  connections_instance.force_feedback = System.IntPtr.Zero;
449  this.connections[tool_instance_index] = connections_instance;
450  return true;
451  }
452 
453  return false;
454  }
455 
456  // Disconnects a tool from a VRPN Tracker server based on the tool index.
457  // Returns true if the VRPN Connection was actually destroyed, false otherwise.
458  public bool DisconnectToolFromTracker(int tool_instance_index) {
459  VRPNToolConnections connections_instance;
460  try {
461  connections_instance = this.connections[tool_instance_index];
462  }
463  catch (Exception) {
464  return false;
465  }
466 
467  if (VRPN.Wrapper.vrpn_c_close_tracker(connections_instance.tracker)) {
468  connections_instance.tracker = System.IntPtr.Zero;
469  this.connections[tool_instance_index] = connections_instance;
470  return true;
471  }
472 
473  return false;
474  }
475 
476  // Disconnects a tool from a VRPN Buttons server based on the tool index.
477  // Returns true if the VRPN Connection was actually destroyed, false otherwise.
478  public bool DisconnectToolFromButtons(int tool_instance_index) {
479  VRPNToolConnections connections_instance;
480  try {
481  connections_instance = this.connections[tool_instance_index];
482  }
483  catch (Exception) {
484  return false;
485  }
486 
487  if (VRPN.Wrapper.vrpn_c_close_button(connections_instance.buttons)) {
488  connections_instance.buttons = System.IntPtr.Zero;
489  this.connections[tool_instance_index] = connections_instance;
490  return true;
491  }
492 
493  return false;
494  }
495  }
496 
497 }
bool DisconnectToolFromTracker(int tool_instance_index)
Definition: VRPNManager.cs:458
static bool vrpn_c_button_is_connected(System.IntPtr device)
System.IntPtr buttons
Definition: VRPNManager.cs:25
bool ConnectToolToTracker(int tool_instance_index, string vrpn_device)
Definition: VRPNManager.cs:366
Vector3 last_workspace_position
Definition: VRPNManager.cs:42
System.IntPtr tracker
Definition: VRPNManager.cs:24
VRPNToolType type
Definition: VRPNManager.cs:36
static bool vrpn_c_force_feedback_doing_okay(System.IntPtr device)
Vector3 last_tracker_position
Definition: VRPNManager.cs:44
static bool vrpn_c_close_button(System.IntPtr device)
VRPNToolConnections(System.IntPtr force_feedback=new IntPtr(), System.IntPtr buttons=new IntPtr(), System.IntPtr tracker=new IntPtr())
Definition: VRPNManager.cs:27
static bool vrpn_c_tracker_is_connected(System.IntPtr device)
delegate void ButtonCallbackDelegate(Int32 button, Int32 state)
static bool vrpn_c_close_force_feedback(System.IntPtr device)
delegate void AnalogCallbackDelegate(VRPN.Wrapper.VRPNAnalogReport report)
VRPN.Wrapper.TrackerCallbackDelegate interactorTrackerDelegate
Definition: VRPNManager.cs:64
GameObject selection_sphere
Definition: VRPNManager.cs:48
bool ConnectToolToForceFeedback(int tool_instance_index, string vrpn_device)
Definition: VRPNManager.cs:333
bool RemoveTool(int tool_instance_index)
Definition: VRPNManager.cs:272
System.IntPtr force_feedback
Definition: VRPNManager.cs:23
static bool vrpn_c_tracker_doing_okay(System.IntPtr device)
VRPNToolType
Definition: VRPNManager.cs:16
static System.IntPtr vrpn_c_open_button(string name, ButtonCallbackDelegate buttonCallbackF)
SingleAtomSelection closest_atom
Definition: VRPNManager.cs:50
static System.IntPtr vrpn_c_open_force_feedback(string name)
VRPN.Wrapper.ButtonCallbackDelegate interactorButtonDelegate
Definition: VRPNManager.cs:65
bool DisconnectToolFromButtons(int tool_instance_index)
Definition: VRPNManager.cs:478
int InstantiateTool(VRPNToolType tool_type)
Definition: VRPNManager.cs:223
delegate void TrackerCallbackDelegate(uint sensor, System.IntPtr pos, System.IntPtr quat)
!WiP Includes FLAGS of GUI.
Definition: UIData.cs:78
void interactorButtonCallback(Int32 button, Int32 state)
Definition: VRPNManager.cs:115
bool ConnectToolToButtons(int tool_instance_index, string vrpn_device)
Definition: VRPNManager.cs:401
VRPN.Wrapper.AnalogCallbackDelegate explorerAnalogDelegate
Definition: VRPNManager.cs:66
static ArtemisManager getArtemisManager()
Definition: UnityMolMain.cs:29
static System.IntPtr vrpn_c_open_tracker(string name, TrackerCallbackDelegate trackerCallbackF)
SingleAtomSelection getClosestAtomGameObject(Vector3 position)
static bool vrpn_c_force_feedback_set_force(System.IntPtr device, float force_x, float force_y, float force_z)
bool DisconnectToolFromForceFeedback(int tool_instance_index)
Definition: VRPNManager.cs:436
static AtomType atomtype
Definition: UIData.cs:139
void interactorTrackerCallback(uint sensor, System.IntPtr pos, System.IntPtr quat)
Definition: VRPNManager.cs:78
static bool vrpn_c_button_doing_okay(System.IntPtr device)
static bool vrpn_c_poll_tracker(System.IntPtr device)
static bool vrpn_c_poll_button(System.IntPtr device)
void send_forces(int nb_forces, int[] indices, float[] coordinates)
GameObject workspaceGo
Definition: VRPNManager.cs:40
Definition: GUIDisplay.cs:66
static GenericManager getCurrentAtomManager()
Definition: UnityMolMain.cs:50
static void vrpn_c_force_feedback_stop(System.IntPtr device)
void explorerAnalogCallback(VRPN.Wrapper.VRPNAnalogReport report)
Definition: VRPNManager.cs:160
static bool vrpn_c_close_tracker(System.IntPtr device)