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





Tag - calculation

Entries feed - Comments feed


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


Calculate the real difference between two angles, keeping the correct sign

1 April 2009

When you build some animations with WPF, Surface or JavaFX you sometimes need to know how evolve an angle. For example, you have the new angle (orientation) of an object and you have store before the last measure of this orientation : how to calculate the evolution ?

A first solution

"This is simple" will you say, just do this :

double difference = secondAngle - firstAngle;

But this snippet leads to errors. This is because the orientation value given is relative to a certain initial value, and restart to 0° if you pass the 360°. Lets give you an example: if the object was oriented at 358° and the user turns it of 5° you will obtain a difference of (3-358=) -355° where you actually wants to find 5....

A better solution

A solution I propose is to consider that the methods is called enough frequently that if the object rotate to the left or to the right it has not enough time to rotate more than 180° (half a tour).

Based on this, we consider that the direction of the rotation is given by the "shortest way". If it shorter to turn to the left to go to the new angle, then we select the angle sign which tells we have turned to the left. It may be easiest to understand by looking atentivly to the image above.

An image is maybe better than word : calculateAnglesBetweenOrientationExemple2

We then have this method in C#:

private double calculateDifferenceBetweenAngles(double firstAngle, double secondAngle)
        double difference = secondAngle - firstAngle;
        while (difference < -180) difference += 360;
        while (difference > 180) difference -= 360;
        return difference;

A case of use

When do use it ? For example when you build a carousel: the user can click on a specific item and the carousel rotate so it is in front of you. You then need to have the correct angle. I found no other way to do it.

Does someone have a better way to proceed ?

Shout it