泥庭

2013年5月26日

マルチタッチで拡大縮小・回転・移動 その3

Filed under: .NET, ストアアプリ, Windows8 — タグ: , , — yone64 @ 8:44 PM

前回前々回の続き。

とりあえず、タッチポイントの中心で拡大縮小・回転できるようにはなったのですが、三角関数とか使いたくないですよね?CompositeTransformが、すべての変形を保持しているので補正が必要になるので、履歴を持つTransformと現在の変形を持つTransformに分ければもう少し話は簡単になります。

XAMLは、下記通り。MatrixTransformとCompositeTransformで変形を表すことで、中心が移動した時の補正を不要にします。

<Ellipse Height="75"  Width="278" Margin="449,306,0,0"  Fill="Red"
         HorizontalAlignment="Left" VerticalAlignment="Top"
         ManipulationMode="All" ManipulationDelta="Ellipse_ManipulationDelta">
    <Ellipse.RenderTransform>
        <TransformGroup>
            <MatrixTransform/>
            <CompositeTransform/>
        </TransformGroup>
    </Ellipse.RenderTransform>
</Ellipse>

コードビハインド側は、TransformGroupの変形をMatrixTransformに移し替えるとともに、CompositeTransformに新たなる変形を設定します。

private void Ellipse_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
    var group = ((UIElement)sender).RenderTransform as TransformGroup;

    var matrix = group.Children[0] as MatrixTransform;
    var composit = group.Children[1] as CompositeTransform;

    matrix.Matrix = group.Value;

    var center = matrix.TransformPoint(new Point(e.Position.X, e.Position.Y));
    composit.CenterX = center.X;
    composit.CenterY = center.Y;

    composit.ScaleX = e.Delta.Scale;
    composit.ScaleY = e.Delta.Scale;

    composit.Rotation = e.Delta.Rotation;

    composit.TranslateX = e.Delta.Translation.X;
    composit.TranslateY = e.Delta.Translation.Y;

}

これで、RoomMetroで発表した内容は全部です。あれから一か月もたってしまった。

2013年5月23日

マルチタッチで拡大縮小・回転・移動 その2

Filed under: .NET, ストアアプリ, Windows8 — タグ: , , — yone64 @ 12:25 AM

前々回の続き。

さてさて、中心点を変えた場合になぜオブジェクトがワープするかというと、下図参照。

image

中央の赤四角を、左上の点で2倍に拡大したものがオレンジの四角です。この拡大の中心を右下の点に移動させると拡大後の四角は緑色のものになります。なので、中心点を移動させた場合、それと同じ方向に(拡大倍率ー1)倍移動させ補正する必要があります。

private void Rectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
    var transform = ((UIElement)sender).RenderTransform as CompositeTransform;
    var diffX = e.Position.X - transform.CenterX;
    var diffY = e.Position.Y - transform.CenterY;

    transform.CenterX = e.Position.X;
    transform.CenterY = e.Position.Y;

    transform.TranslateX += e.Delta.Translation.X + diffX * (transform.ScaleX - 1);
    transform.TranslateY += e.Delta.Translation.Y + diffY * (transform.ScaleY - 1);

    transform.ScaleX *= e.Delta.Scale;
    transform.ScaleY *= e.Delta.Scale;

    transform.Rotation += e.Delta.Rotation;
}

とりあえず、これで拡大時の補正が終了です。同様に回転時の補正もする必要があります。

image

拡大縮小時と同様、中心を左上から右下に移動したケースです。今度はちょっと複雑ですが、中心の移動線の角度+回転角だけ回転させた座標と中心の移動船の角度の座標の差分を補正する必要がでます。

private void Rectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
    var transform = ((UIElement)sender).RenderTransform as CompositeTransform;
    var diffX = e.Position.X - transform.CenterX;
    var diffY = e.Position.Y - transform.CenterY;

    var rad = Math.Atan2(diffY, diffX);
    var d = rad + transform.Rotation * Math.PI / 180;
    var dist = Math.Sqrt(diffX * diffX + diffY * diffY);
    var newX = dist * Math.Cos(d);
    var newY = dist * Math.Sin(d);

    transform.CenterX = e.Position.X;
    transform.CenterY = e.Position.Y;

    transform.ScaleX *= e.Delta.Scale;
    transform.ScaleY *= e.Delta.Scale;

    transform.Rotation += e.Delta.Rotation;

    transform.TranslateX += e.Delta.Translation.X + diffX * (transform.ScaleX - 1) - (diffX - newX) * transform.ScaleX;
    transform.TranslateY += e.Delta.Translation.Y + diffY * (transform.ScaleY - 1) - (diffY - newY) * transform.ScaleY;
}

結果、こんな感じになりました。これでワープしなくなります。ちなみに最後の2行はまとめてもう少し短くなります。

transform.TranslateX += e.Delta.Translation.X - diffX + newX * transform.ScaleX;
transform.TranslateY += e.Delta.Translation.Y - diffY + newY * transform.ScaleY;

#三角関数計算はもう少し簡単になったりするのかな?

2013年5月19日

マルチタッチで拡大縮小・回転・移動

Filed under: .NET, ストアアプリ, Windows8 — タグ: , , , — yone64 @ 4:40 PM

マルチタッチの醍醐味はやっぱり拡大縮小・回転ですよね。
これはManipulationDeltaイベントをハンドルすることで実現することができます。

まず、XAML上で動かしたい対象オブジェクトにCompositeTransformを設定します。

<Rectangle Fill="#FF53F030" HorizontalAlignment="Left" Height="100" Margin="940,188,0,0" Stroke="Black" VerticalAlignment="Top" Width="100" 
           ManipulationMode="All" ManipulationDelta="Rectangle_ManipulationDelta">
    <Rectangle.RenderTransform>
        <CompositeTransform/>
    </Rectangle.RenderTransform>
</Rectangle>

ManipulationDeltaイベントでは、移動差分・拡大縮小差分・回転差分が取得できるので、これをCompositeTransformに設定します。

private void Rectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
    var transform = ((UIElement)sender).RenderTransform as CompositeTransform;

    transform.TranslateX += e.Delta.Translation.X;
    transform.TranslateY += e.Delta.Translation.Y;

    transform.ScaleX *= e.Delta.Scale;
    transform.ScaleY *= e.Delta.Scale;

    transform.Rotation += e.Delta.Rotation;
}

簡単ですね。でも少し操作してみるとわかりますが、拡大縮小および回転の起点が左上で固定されています。これを変更するためには、XAML上でRenderTransformOriginを設定します。”0.5,0.5”を設定すると起点がRectangleの中心になります。

<Rectangle Fill="#FF53F030" HorizontalAlignment="Left" Height="100" Margin="940,188,0,0" Stroke="Black" VerticalAlignment="Top" Width="100" 
           ManipulationMode="All" ManipulationDelta="Rectangle_ManipulationDelta" RenderTransformOrigin="0.5,0.5">
    <Rectangle.RenderTransform>
        <CompositeTransform/>
    </Rectangle.RenderTransform>
</Rectangle>

これの起点をタッチごとに変更するためには、下記通りManipulationDeltaイベントでCompositeTransformのCenterXおよびCenterYを設定するとよいのですが、ことはそんなに単純ではなく…。

private void Rectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
    var transform = ((UIElement)sender).RenderTransform as CompositeTransform;

    transform.CenterX = e.Position.X;
    transform.CenterY = e.Position.Y;

    transform.TranslateX += e.Delta.Translation.X;
    transform.TranslateY += e.Delta.Translation.Y;

    transform.ScaleX *= e.Delta.Scale;
    transform.ScaleY *= e.Delta.Scale;

    transform.Rotation += e.Delta.Rotation;
}

この状態で実行すると、拡大縮小・回転時にRectangleがワープします。残念。

WordPress.com で無料サイトやブログを作成.