QML(Qt)のグラデーションを任意の方向にする

QMLのグラデーションは通常Gradientエレメントを使用しますが、縦方向にしか設定できません。
そんな話題があったので試しに作ってみました。

通常はこんな感じ。
Rectangle {
    width: 100; height: 100
    gradient: Gradient {
        GradientStop { position: 0.0; color: "red" }
        GradientStop { position: 0.33; color: "yellow" }
        GradientStop { position: 1.0; color: "green" }
    }
}

/// ポイント ///
・グラデをかけたい四角をクリップ設定にして、中にグラデをかけた四角を置く
・rotationで中の四角を回転させる(使い勝手がいい)
・親のサイズに合わせて調度良くリサイズをする
・関数でもバインドが働く
・もっと効率いい計算方法あったら教えて下さい

サンプルコード(拡張エレメント込)はこんなかんじです。
エレメント名がMSっぽいとかは気にしたらダメです。
サンプルはウインドウサイズを変更するとグラデの角度が変わります。

実際に使用するときは、親のエレメントのclipをtrueにします。

サンプルのスクリーンショット
qt-gradient-free-angle.png
呼び出し元
import QtQuick 2.0

Rectangle {
    width: 600
    height: 400
    color: "black"

    Rectangle{
        anchors.centerIn: parent
        width: parent.width / 3
        height: parent.height / 3
//        clip: true

        GradientEx{
            id: grad
            gradient: Gradient{
                GradientStop { position: 0.0; color: "red" }
                GradientStop { position: 0.33; color: "yellow" }
                GradientStop { position: 1.0; color: "green" }
            }
            rotation: (2 * (parent.x - 400)) % 360
        }

        //ちゃんとグラデの四角が良いサイズになってるか確認する用の四角(親のclipは解除して確認する)
        Rectangle{
            anchors.fill: parent
            opacity: 0.5
        }
    }

    Text{
        text: "angle=" + grad.rotation
        color: "white"
    }
}

拡張したグラデ
import QtQuick 2.0

Rectangle{
    anchors.centerIn: parent
    width: calcWidth()
    height: calcHeight()

    //ラジアンを予め計算しておく
    property real rad: calcRad()
    //角度は0~90にしないと面倒なので
    function calcRad(){
        var r = rotation;
        while(r > 90){
            r -= 90;
        }
        while(r < 0){
            r += 90;
        }
        return r * Math.PI / 180;
    }
    //0~90度を基準に90度ごとにwidthとheightにかけるcosとsinが入れ替わる
    //なのでマイナス側の-90~0は、入れ替わりになるように90度ずらして判定する
    function calcWidth(){
        var len = 0;
        var r = rotation >= 0 ? rotation : -(rotation - 90)
        if((0 <= r && r <= 90) || (180 < r && r <= 270)){
            len = parent.width * Math.cos(rad) + parent.height * Math.sin(rad);
        }else if((90 < r && r <= 180) || (270 < r && r <= 360)){
            len = parent.width * Math.sin(rad) + parent.height * Math.cos(rad);
        }else{
            len = parent.width * Math.cos(rad) + parent.height * Math.sin(rad);
        }
        return len;
    }
    function calcHeight(){
        var len = 0;
        var r = rotation >= 0 ? rotation : -(rotation - 90)
        if((0 <= r && r <= 90) || (180 < r && r <= 270)){
            len = parent.width * Math.sin(rad) + parent.height * Math.cos(rad);
        }else if((90 < r && r <= 180) || (270 < r && r <= 360)){
            len = parent.width * Math.cos(rad) + parent.height * Math.sin(rad);
        }else{
            len = parent.width * Math.sin(rad) + parent.height * Math.cos(rad);
        }
        return len;
    }
}