Oct 12, 2011

[Tip] Gradientes en cualquier dirección con QML


Para todos aquellos que estén desarrollando programas en QML habrán notado que si aplicamos un gradiente a un rectangulo, este gradiente solo es posible aplicarlo de forma vertical, tal que así:


Pero, ¿Que pasaría si quisiéramos aplicar un gradiente en cualquier angulo posible?, por ejemplo aplicar gradientes en un angulo de 30°.
Pues eso es lo que vamos a ver hoy.
Supongamos que tenemos 2 rectángulos, Rectángulo 1 y Rectángulo 2, siendo Rectángulo 2 hijo de Rectángulo 1, Rectángulo 2 será a quien apliquemos el gradiente y la rotación, el rectángulo tendrá una rotación con respecto a su centro igual a la dirección del gradiente y sus dimensiones deben ser lo suficientemente grandes como para contener a Rectángulo 1, mientras que a Rectángulo 1 la aplicaremos la propiedad clip para no mostrar las áreas sobrantes de Rectángulo 2.
Lo podemos ver más claramente en el siguiente gráfico, el rectángulo de color azul representa al Rectángulo 1 mientras que el rectángulo de color rojo representa al Rectángulo 2:



Del gráfico podemos deducir que 0° ≤ α ≤ 90°.
Podemos entonces armar las ecuaciones de las rectas S1, S2, S3 y S4:

$$S1: \frac{2y-RH}{2x+RW}=\left | \tan \alpha \right |\Rightarrow -2x\left | \tan \alpha \right |+2y=RW\left | \tan \alpha \right |+RH$$

$$S2: \frac{2y+RH}{2x+RW}=-\frac{1}{\left | \tan \alpha \right |}\Rightarrow 2x+2y\left | \tan \alpha \right |=-RW-RH\left | \tan \alpha \right |$$

$$S3: \frac{2y+RH}{2x-RW}=\left | \tan \alpha \right |\Rightarrow 2x\left | \tan \alpha \right |-2y=RW\left | \tan \alpha \right |+RH$$

$$S4: \frac{2y-RH}{2x-RW}=-\frac{1}{\left | \tan \alpha \right |}\Rightarrow 2x+2y\left | \tan \alpha \right |=RW+RH\left | \tan \alpha \right |$$

Luego calculamos los puntos de intersección de las rectas, Q1, Q2 y Q3, dado que Sw = |Q2Q1| y Sh = |Q3Q2|:

$$
Q1:\begin{vmatrix}
-2 \left | \tan \alpha \right | & 2 \\
2 & 2\left | \tan \alpha \right |
\end{vmatrix}\cdot \begin{vmatrix}
x\\
y
\end{vmatrix}=\begin{vmatrix}
RW\left | \tan \alpha \right |+RH \\
-RW-RH \left | \tan \alpha \right |
\end{vmatrix} \left \{ \begin{matrix}
x=-\frac{RW}{2}-RH\left ( \frac{\left | \tan \alpha \right |}{1+\tan^{2}\alpha} \right ) \\
y=\frac{RH}{2}\left ( \frac{1-\tan^{2}\alpha}{1+\tan^{2}\alpha} \right )
\end{matrix} \right.
$$

$$
Q2:\begin{vmatrix}
-2\left | \tan \alpha \right | & 2\\
2 & 2\left | \tan \alpha \right |
\end{vmatrix}\cdot \begin{vmatrix}
x\\
y
\end{vmatrix}=\begin{vmatrix}
RW\left | \tan \alpha \right |+RH\\
RW+RH\left | \tan \alpha \right |
\end{vmatrix}\left \{\begin{matrix}
x=\frac{RW}{2}\left ( \frac{1-\tan^{2}\alpha}{1+\tan^{2}\alpha} \right )\\
y=RW\left ( \frac{\left | \tan \alpha \right |}{1+\tan^{2}\alpha} \right )+\frac{RH}{2}
\end{matrix} \right.
$$

$$
Q3:\begin{vmatrix}
2\left | \tan \alpha \right | & -2\\
2 & 2\left | \tan \alpha \right |
\end{vmatrix}\cdot \begin{vmatrix}
x\\
y
\end{vmatrix}=\begin{vmatrix}
RW\left | \tan \alpha \right |+RH\\
RW+RH\left | \tan \alpha \right |
\end{vmatrix}\left \{ \begin{matrix}
x=\frac{RW}{2}+RH\left ( \frac{\left | \tan \alpha \right |}{1+\tan^{2}\alpha} \right )\\
y=-\frac{RH}{2}\left ( \frac{1-\tan^{2}\alpha}{1+\tan^{2}\alpha} \right )
\end{matrix} \right.
$$

Luego calculamos los vectores correspondientes a Sw y Sh:

$$Sw:\left (\frac{RW+RH\left| \tan\alpha\right|}{1+\tan^{2}\alpha},\frac{\left| \tan\alpha\right|\left ( RW+RH\left| \tan\alpha\right| \right )}{1+\tan^{2}\alpha}\right )$$

$$Sh:\left (\frac{\left| \tan\alpha\right|\left ( RW\left| \tan\alpha\right|+RH \right )}{1+\tan^{2}\alpha},\frac{-\left(RW\left| \tan\alpha\right|+RH \right )}{1+\tan^{2}\alpha}\right )$$

Y calculamos sus módulos:

Sw:Sh:
$$\frac {\sqrt{\left ( RW+RH\left | \tan\alpha \right | \right )^2+\tan^2\alpha\left ( RW+RH\left | \tan\alpha \right | \right )^2}}{1+\tan^2\alpha}$$ $$\frac {\sqrt{\tan^2\alpha\left ( RW\left | \tan\alpha \right |+RH \right )^2+\left ( RW\left | \tan\alpha \right |+RH \right )^2}}{1+\tan^2\alpha}$$
$$\frac {\left | RW+RH\left | \tan\alpha \right | \right |}{\sqrt{1+\tan^2\alpha}}$$ $$\frac {\left | RW\left | \tan\alpha \right |+RH \right |}{\sqrt{1+\tan^2\alpha}}$$
$$\left | RW+RH\left | \tan\alpha \right | \right |\cdot \left | \cos\alpha \right |$$ $$\left | RW\left | \tan\alpha \right |+RH \right |\cdot \left | \cos\alpha \right |$$

Y finalmente obtenemos las ecuaciones necesarias para calcular las dimensiones del rectangulo con gradiente para una determinada dirección:

$$Sw=RW\left | \cos\alpha \right |+RH\left | \sin\alpha \right |$$
$$Sh=RW\left | \sin\alpha \right |+RH\left | \cos\alpha \right |$$

Y finalmente, el código fuente del ejemplo:

import QtQuick 1.0

Rectangle
{
    id: recParent
    width: 640
    height: 480
    color: "#000000"

    Rectangle
    {
        id: recGradientContainer
        width: 400
        height: 300
        clip: true
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter
        property real gradientRotation: 30

        Rectangle
        {
            id: recGradient

            // Sw = RW |cos a| + RH |sin a|
            // Sh = RW |sin a| + RH |cos a|
            width: recGradientContainer.width * recGradient.cos + recGradientContainer.height * recGradient.sin
            height: recGradientContainer.width * recGradient.sin + recGradientContainer.height * recGradient.cos

            rotation: recGradientContainer.gradientRotation
            smooth: true
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.verticalCenter: parent.verticalCenter

            // Convertimos grados a radianes.
            property real rotationRadians: recGradient.rotation * Math.PI / 180

            // Precalculamos seno y coseno para el angulo del gradiente.
            property real cos: Math.abs(Math.cos(recGradient.rotationRadians))
            property real sin: Math.abs(Math.sin(recGradient.rotationRadians))

            gradient: Gradient
            {
                GradientStop
                {
                    position: 0
                    color: "#ff0000"
                }

                GradientStop
                {
                    position: 1
                    color: "#0000ff"
                }
            }
        }
    }
}

No comments:

Post a Comment