Yet another blog about WPF, Surface, SL, MVVM, NUI....






How to scale around a specific point and not the center of the Element

11 October 2009

The problem

The most popular controls which has been brought by the Microsoft SDK is certainly the scatterView. Each item is positioned at a random place with a random orientation.

You can then rotate, move or scale them with your fingers. Here we will focus on this last point : the scaling. This is a really nice feature and you may wants to put it in your application (it may also be replace my a mouse wheel or stylus events, etc.).

If an user wants to zoom-in on a specific part of the presented items, he wills do a 'scale manipulation' with it's fingers on the specific part.

Simple, will you think : we just have to change the width and the height of the control based on the scale delta ! But the problem is that, the control will grow but the specific part wanted by the user will no more be under it's fingers. A figure worth a thousand words :
Schema example

My solution

Here we are going to scale a scatterViewItem with the property 'CanMove' set to false. We do it because, the scatterView item does already what we wants and this is done by a translation.

Also we are going to use a Affine2DManipulationProcessor which will gives us the scale value for a manipulation done by multiple fingers. If some are catching stylus events, you could use a ManipulationProcessor from the multiTouch SDK (available here :

The XAML :

<s:ScatterView VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
      <s:ScatterViewItem x:Name="_myObjectToScale" Orientation="0" CanRotate="False" 
            CanScale="False" CanMove="False"
            Center="512.0,384.0"  ShowsActivationEffects="False"
         <Image Source="Resources/myself.jpg" />

The code :

private Affine2DManipulationProcessor _ourManipProc;
public Affine2DManipulationProcessor OurManipProc { 
   get { return _ourManipProc; } 
   set { _ourManipProc = value; }
public SurfaceWindow1()
    DataContext = this;
    _ourManipProc = new Affine2DManipulationProcessor(Affine2DManipulations.Scale, this);
    //Catch the event from our manipulation processor
    OurManipProc.Affine2DManipulationDelta += OurManipProc_Affine2DManipulationDelta;
private void _myObjectToScale_ContactDown(object sender, ContactEventArgs e)
    //this contact is tracked by ou MP
private void _myObjectToScale_ContactUp(object sender, ContactEventArgs e)
    //this contact is no more tracked by ou MP

Then the important part, the Affine2DManipulationDelta handler which will do what we wants, I will describe it below.

void OurManipProc_Affine2DManipulationDelta(object sender, Affine2DOperationDeltaEventArgs e)
    double scaleDelta = e.ScaleDelta;
    if (scaleDelta == 1.0) return;
    Point manipOrigin = e.ManipulationOrigin;
    Point oldCenter = new Point(_myObjectToScale.Center.X, _myObjectToScale.Center.Y);
    double oldHeight = _myObjectToScale.ActualHeight;
    double newHeight = _myObjectToScale.ActualHeight * scaleDelta;
    double oldWidth = _myObjectToScale.ActualWidth;
    double newWidth = _myObjectToScale.ActualWidth * scaleDelta;
    _myObjectToScale.Height = newHeight;
    _myObjectToScale.Width = newWidth;
    double ratioX = Math.Abs(manipOrigin.X - oldCenter.X) / (oldWidth / 2);
    double newCenterXD = ratioX
        * Math.Sign(oldCenter.X - manipOrigin.X) * (newWidth - oldWidth) / 2;
    double ratioY = Math.Abs(manipOrigin.Y - oldCenter.Y) / (oldHeight / 2);
    double newCenterYD = ratioY *
        Math.Sign(oldCenter.Y - manipOrigin.Y) * (newHeight - oldHeight) / 2;
    if (scaleDelta > 1.0)
        _myObjectToScale.Center += new Vector(newCenterXD, newCenterYD);
        _myObjectToScale.Center += new Vector(newCenterXD, newCenterYD);


First we need to calculate the new size of our control. This is done by multiplying it's actual size by the scaleDelta gived by our processor.

Then we store some interesting values as the old size, the old center position, etc.

Then we calculate the ration for X and for Y. What is it ? It's ratio of the aimed point (the point on top of which the manipulation is done) and the half of the control size. But why do we need it ? Because we wants the controls to grow on each side of the aimed point, not only the one near the center. If we does not calculate this, one side of the control would stay at the same position during our manipulation. algo explanation

Next we calculate the center delta which is the translation we must operate on our control for the focused point to stay under our fingers (or mouse pointer, or stylus, whatever you wants :D).

We finaly apply all this measure to our control. That's it !

kick it on Shout it


GUI to NUI : representations and manipulation of OLAP data in 3D

21 July 2009


Here is a little post to show you a little video presenting the project I have worked on during my 6 months of training. I am very proud of it :) :

The subject was to find the new way of representations and manipulations of OLAP Data without using a keyboard or a mouse.
This is done in 3D on the Microsoft Surface plateform.

The technologies involved are :

  1. Microsoft Surface for the NUI (Natural User Interface),
  2. (M)Ogre to create the 3D World,
  3. OLAP for the acquisition of datas.

Here are some links for those interested :

  1. What is OLAP ? (wikipedia)
  2. What are the NUI ? (wikipedia)
  3. What is Ogre the 3D engine ?
  4. What is Microsoft Surface ?
  5. What is the company in which I have done my training ?

People who worked on it :

  1. Development: Jonathan ANTOINE
  2. Supervision of the project : Elise DUPONT
  3. 3D Expert : Laurent TRUDU

Enjoy !

kick it on

Shout it