Workshop Examples

WARNING! AVERTISSEMENT! ¡CUIDADO!
This project page contains code that is out of date!

HTP Workshop


You may download a pdf version of the presentation given during the workshop here: <To be added>

The Study

The study consists of three stages: a training workshop, a session with the experimenter and a session in which you develop your own application. For more information, check the consent form: HTP API Study Consent Form (pdf)

The workshops will be arranged in times that accommodate all participants, so far only one has been scheduled. If a participant is unable to attend, another workshop will be arranged.

Workshop Dates:

  • Monday, March 28th, 2011 at 5:00pm - Interactions Lab, MS 680.
  • Monday, April 4th, 2011 at 5:00pm - Interactions Lab, MS 680.
  • Tuesday, April 5th, 2011 at 5:00pm - Interactions Lab, MS 680.


Low Level Programming

The following example illustrates the simplest application that can be created with the HTP. Here we retrieve an HTP that has already been saved as an xml file and we create a simple loop in which we reduce the height as a function of the pressure. This is only used as a way to explain the basis of all the concepts behind the API. When working with the Microsoft Surface, most elements in the low level will work as getters only.

  1. HTPManager manager = HTPManager.Instance;
  2. HTP h = m.GetHTP(0xEF);
  3.  
  4. while(true)
  5. {
  6.      Console.WriteLine(h.Pressure);
  7.      h.Height = 1 – h.Pressure;
  8. }

However, the true capabilities of the low level of the HTP API become relevant when using events. If you programmed with WPF before, you are probably familiar with events such as MouseDown and MouseUp, which in the surface become ContactDown, ContactChanged and ContactUp. The HTP extends the events from the surface and allows events for HTPDown (when the HTP is placed on the table), HTPChanged (when the HTP is moved) and HTPUp (when the HTP is outside the surface).

  1. HTPManager manager = HTPManager.Instance;
  2. HTP htp;
  3.  
  4. this.manager.RegisterWindow(this, this.grid);
  5. htp = this.manager.GetHTP(0xEF);
  6. htp.HTPDown += new HTPEventHandler(htp_HTPDown);
  7. htp.HTPChanged += new HTPEventHandler(htp_HTPChanged);
  8. htp.HTPUp += new HTPEventHandler(htp_HTPUp);
  9.        :
  10.         void htp_HTPUp(object sender, HTPEventArgs e)
  11.         {
  12.             this.ellipse1.Visibility = Visibility.Hidden;
  13.         }
  14.  
  15.         void htp_HTPChanged(object sender, HTPEventArgs e)
  16.         {
  17.             DownAndChanged(e);
  18.         }
  19.  
  20.         void htp_HTPDown(object sender, HTPEventArgs e)
  21.         {
  22.             DownAndChanged(e);
  23.         }
  24.  
  25.         void DownAndChanged(HTPEventArgs e)
  26.         {
  27.             this.ellipse1.Visibility = Visibility.Visible;
  28.             this.ellipse1.RenderTransform = new TranslateTransform(e.CenterPoint.X - this.ellipse1.Width / 2, e.CenterPoint.Y - this.ellipse1.Height / 2);
  29.         }

Medium Level Programming

We can recreate the same case in the previous example by using haptic behaviors.

  1. HTPManager m = m.Instance);
  2. HTP h = m.GetHTP(0xEF);
  3.  
  4. h.AddHeightBehavior(new SoftnessBehavior(0.5));
  5. h.StartHapticLoop();

We can then make more interesting haptic simulations by stacking different haptic behaviors and changing their ratios.

  1. HTPManager m = m.Instance;
  2. HTP h = m.GetHTP(0xEF);
  3.  
  4. h.AddHeightBehavior(new SoftnessBehavior(0.5));
  5. OscillationBehavior o = new OscillationBehavior(0.03);
  6. // The full height of the rod is shared, twice as much for the oscillation than the softness
  7. o.Ratio = 2;
  8. h.AddHeightBehavior(o);
  9. // Make sure you always start the haptic loop
  10. h.StartHapticLoop();

As a reminder, different behaviors you can use include:

  • SoftnessBehavior (adjustable softness level).
  • OscillationBehavior (adjustable frequency).
  • BreakyBehavior (adjustable number of breakpoints).
  • IntensityBehavior (value given will be the height always, useful for full control of height values).
  • SoftBehaviorInverse (adjustable softness).
  • Random.

Medium Level and Contact Events

Working with the middle abstraction level, you can also start using events that relate to what the HTP does on the table. In order to get access to these events, make sure you add the HTP Manager to the canvas you will be working on.

It is important to note that the HTP Manager automatically does hit testing to determine the behavior that the HTP should have. If you want to change the behavior of the HTP manually, make sure you disable hit testing.

In this example, we extend the previous application that implemented Contact Events and change one of the functions:

  1. void DownAndChanged(HTPEventArgs e)
  2.         {
  3.             this.ellipse1.RenderTransform = new TranslateTransform(e.CenterPoint.X - this.ellipse1.Width/2, e.CenterPoint.Y - this.ellipse1.Height/2);
  4.             h.HeightBehaviors.Clear();
  5.             h.FrictionBehaviors.Clear();
  6.             if (e.CenterPoint.X > 512)
  7.             {
  8.                 this.h.AddHeightBehavior(new SoftnessBehavior(0.5));
  9.             }
  10.             else
  11.             {
  12.                 this.h.AddHeightBehavior(new SoftBehaviorInverse(0.5));
  13.             }
  14.          }

Now depending on where that specific HTP is placed on the table, it will react differently to the pressure applied.

High Level Programming

The high level programming features three different types of widgets: shapes, images and buttons. Widgets with varying opacities can be stacked on top of each other to create combined behaviors.

Programming Shapes

Shapes are the easiest high level widget to program with. They can be very fun, all you need to do is create a shape either in cs code or in xaml code and associate it to an HTPShapeBox.

  1. HTPManager m = m.Instance;
  2. // Create an Ellipse
  3.  Ellipse e1 = new Ellipse();
  4.  e1.Stroke = Brushes.Black;
  5.  e1.StrokeThickness = 4;
  6.  e1.Width = 210;
  7.  e1.Height = 210;
  8.  e1.Fill = Brushes.Crimson;
  9.  
  10. HTPShape shape = new HTPShape(e1);
  11. Shape.AddHeightBehavior(new OscillationBehavior(0.5));
  12. m.AddToCanvas(shape);
  13. this.canvas.Children.Add(m);

Programming Images

Haptic Images are a great way of creating a very basic application using haptics that directly map to an image. Each behavior has an image associated to it and the grayscale value of the current pixel is mapped from 0 to 1. Because of the complexity necessary to have these images working, we discourage the use of xaml code.

It is also important to note that you need to provide a path for the images you use. A very simple solution to this is to place the images in \bin\Debug and use the following line of code:

string filePath = System.IO.Directory.GetCurrentDirectory() + "\\";

You can then append the name of the file to this path.

We now illustrate an example of a haptic image, in which a map is displayed and different behaviors are associated

  1. HTPManager m = m.Instance;
  2.  
  3. // Get current application folder
  4. string filePath = System.IO.Directory.GetCurrentDirectory() + "\\";
  5. // Create new image widget
  6. HTPImage image = new HTPImage(filePath + "map.png");
  7.  
  8. // Add a height map to the image
  9. IntensityBehavior b1 = new IntensityBehavior();
  10. b1.IntensityMapping = new SpatialBehaviorMapping(filePath + "heightMap.png");
  11. image.AddHeightBehavior(b1);
  12. image.AddMapping(b1.IntensityMapping);
  13.  
  14. // Add an oscillation map to the image
  15. OscillationBehavior b2 = new OscillationBehavior();
  16. b2.FrequencyMapping = new SpatialBehaviorMapping(filePath + "oscillationMap.png", 0.2);
  17. image.AddHeightBehavior(b2);
  18. image.AddMapping(b2.FrequencyMapping);
  19.  
  20. // Add a softness map to the image
  21. SoftnessBehavior b3 = new SoftnessBehavior();
  22. b3.SoftnessMapping = new SpatialBehaviorMapping(filePath + "softnessMap.png");
  23. image.AddHeightBehavior(b3);
  24. image.AddMapping(b3.SoftnessMapping);
  25.  
  26. // Add image to manager canvas
  27. m.AddToCanvas(image);
  28. // Add manager to general canvas.
  29. canvas.Children.Add(m);

Buttons

Haptic Buttons consist of three haptic images: inactive (no HTPs are on top), hover (an HTP hovers but still does not press) and pressed (enough pressure is applied on the HTP). The default pressure value that makes a button be considered "pressed" is 0.5.

In this example we illustrate a simple button that always exhibits the same behavior and changes visuals as it gets pressed.

  1. HTPManager m = m.Instance;
  2.  
  3. string filePath = System.IO.Directory.GetCurrentDirectory() + "\\";
  4. HTPImage inactiveImage = new HTPImage(filePath + "inactiveButton.png");
  5. HTPImage hoverImage = new HTPImage(filePath + "hoverButton.png");
  6. HTPImage pressedImage = new HTPImage(filePath + "pressedButton.png");
  7.  
  8. SoftnessBehavior behavior = new SoftnessBehavior();
  9. behavior.SoftnessMapping = new SpatialBehaviorMapping(filePath + "inactiveButton.png");
  10. hoverImage.AddHeightBehavior(behavior);
  11. hoverImage.AddMapping(behavior.SoftnessMapping);
  12. pressedImage.AddMapping(behavior.SoftnessMapping);
  13.  
  14. HTPButton b = new HTPButton(this.inactiveImage, this.hoverImage, this.pressedImage);
  15. b.ButtonBecamePressed += new BeingPressedHandler(b_ButtonBecamePressed);
  16. b.ButtonBecameReleased += new BeingPressedHandler(b_ButtonBecameReleased);
  17. m.AddToCanvas(b);
  18. this.canvas.Children.Add(m);
  19. :
  20. void b_ButtonBecameReleased(object sender, EventArgs e)
  21. {
  22.     Console.WriteLine("RELEASED");
  23. }
  24.  
  25. void b_ButtonBecamePressed(object sender, EventArgs e)
  26. {
  27.     Console.WriteLine("PRESSED!");
  28. }

Sample Applications

You may download the class samples here: Class Samples (zip)
The big application used for demonstration: Large Application Sample (zip)
The Behavior Lab: HTP Behavior Lab