Example #1
0
        //------------------变形方法和其辅助函数 End-----------------------------------------

        // 三种变形的并行版本
        // 变换思路和代码基本同前,只将为目标图每个格点赋像素值的步骤进行并行,即每个格点同时
        // 计算其在原图中对应的坐标,并查找像素信息
        // 故只将串行的两重for,转换为并行的循环

        public static byte[,,] RotateTwistImgParallel(byte[,,] img, InterpolationFunc interpolationFunc,
                                                      double maxAngle, double radius,
                                                      double centerX, double centerY)
        {
            int height = img.GetLength(0);
            int width  = img.GetLength(1);

            byte[,,] imgTwisted = new byte[height, width, img.GetLength(2)];
            System.Threading.Tasks.Parallel.For(0, height * width, index => {
                int i           = index / width;
                int j           = index % width;
                double distance = Math.Sqrt((i - centerX) * (i - centerX) + (j - centerY) * (j - centerY));
                if (distance > radius)
                {
                    for (int channel = 0; channel < 3; channel++)
                    {
                        imgTwisted[i, j, channel] = img[i, j, channel];
                    }
                    return;
                }
                double angle = maxAngle * (radius - distance) / radius;
                double x     = Math.Cos(angle) * (i - centerX) - Math.Sin(angle) * (j - centerY) + centerX;
                double y     = Math.Sin(angle) * (i - centerX) + Math.Cos(angle) * (j - centerY) + centerY;
                for (int channel = 0; channel < 3; channel++)
                {
                    imgTwisted[i, j, channel] = interpolationFunc(img, x, y, channel);
                }
            });
            return(imgTwisted);
        }
Example #2
0
        //------------------插值方法 End-----------------------------------------

        // 变形方法 参数格式byte[,,]img, InterpolationFunc interpolationFunc, 其他变形相关参数 返回值byte[,,]

        // maxAngle弧度制,在前端中,为了用户友好,规定写入角度值,并且由前端完成角度弧度转换这样的简单逻辑
        public static byte[,,] RotateTwistImg(byte[,,] img, InterpolationFunc interpolationFunc,
                                              double maxAngle, double radius,
                                              double centerX, double centerY)
        {
            int height = img.GetLength(0);
            int width  = img.GetLength(1);

            byte[,,] imgTwisted = new byte[height, width, img.GetLength(2)];
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    // 按照变化公式,计算目标图(i,j)应到原图哪个位置取像素信息
                    double distance = Math.Sqrt((i - centerX) * (i - centerX) + (j - centerY) * (j - centerY));
                    if (distance > radius)
                    {
                        for (int channel = 0; channel < 3; channel++)
                        {
                            imgTwisted[i, j, channel] = img[i, j, channel];
                        }
                        continue;
                    }
                    // 原始公式 angle = maxAngle * (radius - distance) / radius, 化简防止radius distance差距过大大数吃小数
                    double angle = maxAngle * (1 - distance / radius);
                    double x     = Math.Cos(angle) * (i - centerX) - Math.Sin(angle) * (j - centerY) + centerX;
                    double y     = Math.Sin(angle) * (i - centerX) + Math.Cos(angle) * (j - centerY) + centerY;
                    for (int channel = 0; channel < 3; channel++)
                    {
                        imgTwisted[i, j, channel] = interpolationFunc(img, x, y, channel);
                    }
                }
            }
            return(imgTwisted);
        }
Example #3
0
        public TransformBindable(Bindable <TValue> targetBindable, InterpolationFunc <TValue> interpolationFunc)
        {
            this.targetBindable    = targetBindable;
            this.interpolationFunc = interpolationFunc ?? Interpolation <TValue> .ValueAt;

            TargetMember = $"{targetBindable.GetHashCode()}.Value";
        }
Example #4
0
            static GenericInterpolation()
            {
                const string interpolation_method = nameof(GenericInterpolation <TEasing> .ValueAt);

                var parameters = typeof(InterpolationFunc <TValue, TEasing>)
                                 .GetMethod(nameof(InterpolationFunc <TValue, TEasing> .Invoke))
                                 ?.GetParameters().Select(p => p.ParameterType).ToArray();

                MethodInfo valueAtMethod = typeof(GenericInterpolation <TEasing>).GetMethod(interpolation_method, parameters);

                if (valueAtMethod != null)
                {
                    FUNCTION = (InterpolationFunc <TValue, TEasing>)valueAtMethod.CreateDelegate(typeof(InterpolationFunc <TValue, TEasing>));
                }
                else
                {
                    var typeRef = FormatterServices.GetSafeUninitializedObject(typeof(TValue)) as IInterpolable <TValue>;

                    if (typeRef == null)
                    {
                        throw new NotSupportedException($"Type {typeof(TValue)} has no interpolation function. Implement the interface {typeof(IInterpolable<TValue>)} interface on the object.");
                    }

                    FUNCTION = typeRef.ValueAt;
                }
            }
        public TransformBindable(Bindable <TValue> targetBindable)
        {
            this.targetBindable = targetBindable;
            interpolationFunc   = Interpolation.ValueAt;

            TargetMember = $"{targetBindable.GetHashCode()}.Value";
        }
Example #6
0
        /// <summary>
        /// Creates a new instance operating on a property or field of <typeparamref name="T"/>. The property or field is
        /// denoted by its name, passed as <paramref name="propertyOrFieldName"/>.
        /// By default, an interpolation method "ValueAt" from <see cref="Interpolation"/> with suitable signature is
        /// picked for interpolating between <see cref="Transform{TValue}.StartValue"/> and
        /// <see cref="Transform{TValue}.EndValue"/> according to <see cref="Transform.StartTime"/>,
        /// <see cref="Transform.EndTime"/>, and a current time.
        /// </summary>
        /// <param name="propertyOrFieldName">The property or field name to be operated upon.</param>
        public TransformCustom(string propertyOrFieldName)
        {
            TargetMember = propertyOrFieldName;

            accessor = getAccessor(propertyOrFieldName);
            Trace.Assert(accessor.Read != null && accessor.Write != null, $"Failed to populate {nameof(accessor)}.");

            interpolationFunc = Interpolation.ValueAt;
        }
Example #7
0
 static TransformCustom()
 {
     interpolation_func =
         (InterpolationFunc<TValue>)typeof(Interpolation).GetMethod(
             nameof(Interpolation.ValueAt),
             typeof(InterpolationFunc<TValue>)
                 .GetMethod(nameof(InterpolationFunc<TValue>.Invoke))
                 .GetParameters().Select(p => p.ParameterType).ToArray()
         )?.CreateDelegate(typeof(InterpolationFunc<TValue>));
 }
        public TransformBindable(Bindable <TValue> targetBindable)
        {
            this.targetBindable = targetBindable;

            // Lambda expression is used so that the delegate is cached (see: https://github.com/dotnet/roslyn/issues/5835)
            interpolationFunc = (double d, TValue value, TValue tValue, double time, double endTime, in TEasing type)
                                => Interpolation.ValueAt(d, value, tValue, time, endTime, in type);

            TargetMember = $"{targetBindable.GetHashCode()}.Value";
        }
        /// <summary>
        /// Creates a new instance operating on a property or field of <typeparamref name="T"/>. The property or field is
        /// denoted by its name, passed as <paramref name="propertyOrFieldName"/>.
        /// By default, an interpolation method "ValueAt" from <see cref="Interpolation"/> with suitable signature is
        /// picked for interpolating between <see cref="Transform{TValue}.StartValue"/> and
        /// <see cref="Transform{TValue}.EndValue"/> according to <see cref="Transform.StartTime"/>,
        /// <see cref="Transform.EndTime"/>, and a current time.
        /// </summary>
        /// <param name="propertyOrFieldName">The property or field name to be operated upon.</param>
        public TransformCustom(string propertyOrFieldName)
        {
            TargetMember = propertyOrFieldName;

            accessor = getAccessor(propertyOrFieldName);
            Trace.Assert(accessor.Read != null && accessor.Write != null, $"Failed to populate {nameof(accessor)}.");

            // Lambda expression is used so that the delegate is cached (see: https://github.com/dotnet/roslyn/issues/5835)
            interpolationFunc = (double d, TValue value, TValue tValue, double time, double endTime, in TEasing type)
                                => Interpolation.ValueAt(d, value, tValue, time, endTime, in type);
        }
Example #10
0
        /// <summary>
        /// Creates a new instance operating on a property or field of <see cref="T"/>. The property or field is
        /// denoted by its name, passed as <paramref name="propertyOrFieldName"/>.
        /// By default, an interpolation method "ValueAt" from <see cref="Interpolation"/> with suitable signature is
        /// picked for interpolating between <see cref="Transform{TValue}.StartValue"/> and
        /// <see cref="Transform{TValue}.EndValue"/> according to <see cref="Transform.StartTime"/>,
        /// <see cref="Transform.EndTime"/>, and a current time.
        /// Optionally, or when no suitable "ValueAt" from <see cref="Interpolation"/> exists, a custom function can be supplied
        /// via <paramref name="interpolationFunc"/>.
        /// </summary>
        /// <param name="propertyOrFieldName">The property or field name to be operated upon.</param>
        /// <param name="interpolationFunc">
        /// The function to be used for interpolating between <see cref="Transform{TValue}.StartValue"/> and
        /// <see cref="Transform{TValue}.EndValue"/> according to <see cref="Transform.StartTime"/>,
        /// <see cref="Transform.EndTime"/>, and a current time.
        /// If null, an interpolation method "ValueAt" from <see cref="Interpolation"/> with a suitable signature is picked.
        /// If none exists, then this parameter must not be null.
        /// </param>
        public TransformCustom(string propertyOrFieldName, InterpolationFunc<TValue> interpolationFunc = null)
        {
            TargetMember = propertyOrFieldName;

            accessor = getAccessor(propertyOrFieldName);
            Trace.Assert(accessor.Read != null && accessor.Write != null, $"Failed to populate {nameof(accessor)}.");

            this.interpolationFunc = interpolationFunc ?? interpolation_func;

            if (this.interpolationFunc == null)
                throw new InvalidOperationException(
                    $"Need to pass a custom {nameof(interpolationFunc)} since no default {nameof(Interpolation)}.{nameof(Interpolation.ValueAt)} exists.");
        }
    public static void DrawCatmullPath(List<Transform> points, InterpolationFunc sampler, int samples)
    {
        if (!PreDrawPath(points, 4))
            return;

        float sampleInterval = 1.0f / (float)samples;

        int p0, p1, p2, p3;

        for (int i = 0; i < points.Count; ++i)
        {
            p1 = i;

            p0 = p1 - 1;
            if (p0 < 0)
                p0 = points.Count - 1;

            p2 = p1 + 1;
            if (p2 >= points.Count)
                p2 = 0;

            p3 = p2 + 1;
            if (p3 >= points.Count)
                p3 = 0;

            Vector3 sample, prevSample;

            prevSample = points[p1].position;

            for (int j = 1; j <= samples; ++j)
            {
                float t = j * sampleInterval;
                sample = sampler(points[p0].position,
                                 points[p1].position,
                                 points[p2].position,
                                 points[p3].position, t);

                Handles.DrawLine(prevSample, sample);

                prevSample = sample;
            }
        }
    }
Example #12
0
        public static byte[,,] TPSImgParallel(byte[,,] img, InterpolationFunc interpolationFunc,
                                              double[,] pointPair)
        {
            // 置矩阵,高斯消元解系数同串行版本
            if (pointPair.GetLength(1) != 4)
            {
                return(null); // Error pointPair
            }
            int pointNumber = pointPair.GetLength(0);

            double[,] Y = new double[pointNumber + 3, 2];
            for (var i = 0; i < pointNumber; i++)
            {
                Y[i, 0] = pointPair[i, 2];
                Y[i, 1] = pointPair[i, 3];
            }

            double[,] L = new double[pointNumber + 3, pointNumber + 3];
            for (var j = 0; j < pointNumber; j++)
            {
                L[pointNumber, j] = 1;
                L[j, pointNumber] = 1;
            }
            for (var i = pointNumber + 1; i < pointNumber + 3; i++)
            {
                for (var j = 0; j < pointNumber; j++)
                {
                    L[i, j] = pointPair[j, i - pointNumber - 1];
                    L[j, i] = L[i, j];
                }
            }
            for (var i = 0; i < pointNumber; i++)
            {
                for (var j = 0; j <= i; j++)
                {
                    if (j == i)
                    {
                        L[i, j] = 0;
                        break;
                    }
                    L[i, j] = RadialbasisByPoint(pointPair[i, 0], pointPair[i, 1], pointPair[j, 0], pointPair[j, 1]);
                    L[j, i] = L[i, j];
                }
            }
            // 传入高斯消元函数的为引用,会被函数体修改矩阵值,原本应使用
            // double[,] coe = GaussianElimination(L.Clone(), Y.Clone());
            // 但LY不再使用,故为节约耗时,不clone
            double[,] coe = GaussianElimination(L, Y);
            if (coe == null)
            {
                return(null);
            }

            // 以下开始并行
            int height = img.GetLength(0);
            int width  = img.GetLength(1);

            byte[,,] imgTPSed = new byte[height, width, 3];

            System.Threading.Tasks.Parallel.For(0, height * width, index => {
                double x;
                double y;
                int i = index / width;
                int j = index % width;
                x     = coe[pointNumber, 0] + coe[pointNumber + 1, 0] * i + coe[pointNumber + 2, 0] * j;
                y     = coe[pointNumber, 1] + coe[pointNumber + 1, 1] * i + coe[pointNumber + 2, 1] * j;
                double[,] weightedUArray = new double[pointNumber, 4]; // 分正负相消累计,防止大数吃小数
                double u;
                double weightedUX;
                double weightedUY;
                int posUXcount = 0;
                int negUXcount = 0;
                int posUYcount = 0;
                int negUYcount = 0;
                for (var wCount = 0; wCount < pointNumber; wCount++)
                {
                    u          = RadialbasisByPoint(i, j, pointPair[wCount, 0], pointPair[wCount, 1]);
                    weightedUX = u * coe[wCount, 0];
                    weightedUY = u * coe[wCount, 1];
                    if (weightedUX > 0)
                    {
                        weightedUArray[posUXcount, 0] = weightedUX;
                        posUXcount++;
                    }
                    else
                    {
                        weightedUArray[negUXcount, 1] = weightedUX;
                        negUXcount++;
                    }

                    if (weightedUY > 0)
                    {
                        weightedUArray[posUYcount, 2] = weightedUY;
                        posUYcount++;
                    }
                    else
                    {
                        weightedUArray[negUYcount, 3] = weightedUY;
                        negUYcount++;
                    }
                }
                posUXcount--; posUYcount--; negUXcount--; negUYcount--;
                while (posUXcount >= 0 && negUXcount >= 0)
                {
                    if (x > 0)
                    {
                        x += weightedUArray[negUXcount, 1];
                        negUXcount--;
                    }
                    else
                    {
                        x += weightedUArray[posUXcount, 0];
                        posUXcount--;
                    }
                }
                while (posUXcount >= 0)
                {
                    x += weightedUArray[posUXcount, 0];
                    posUXcount--;
                }
                while (negUXcount >= 0)
                {
                    x += weightedUArray[negUXcount, 1];
                    negUXcount--;
                }

                while (posUYcount >= 0 && negUYcount >= 0)
                {
                    if (y > 0)
                    {
                        y += weightedUArray[negUYcount, 3];
                        negUYcount--;
                    }
                    else
                    {
                        y += weightedUArray[posUYcount, 2];
                        posUYcount--;
                    }
                }
                while (posUYcount >= 0)
                {
                    y += weightedUArray[posUYcount, 2];
                    posUYcount--;
                }
                while (negUYcount >= 0)
                {
                    y += weightedUArray[negUYcount, 3];
                    negUYcount--;
                }

                if (x < 0 || x >= height || y < 0 || y > width)
                {
                    return;
                }
                for (var channel = 0; channel < 3; channel++)
                {
                    imgTPSed[i, j, channel] = interpolationFunc(img, x, y, channel);
                }
            });


            return(imgTPSed);
        }
Example #13
0
        public static byte[,,] DistortImgParallel(byte[,,] img, InterpolationFunc interpolationFunc,
                                                  double radius,
                                                  double centerX, double centerY,
                                                  bool isAdjustPillowDistort)
        {
            int height = img.GetLength(0);
            int width  = img.GetLength(1);

            byte[,,] imgDistorted = new byte[height, width, img.GetLength(2)];
            if (isAdjustPillowDistort)   // 校正枕形畸变,即对图像做桶形畸变
            {
                System.Threading.Tasks.Parallel.For(0, height * width, index => {
                    int i           = index / width;
                    int j           = index % width;
                    double distance = Math.Sqrt((i - centerX) * (i - centerX) + (j - centerY) * (j - centerY));
                    if (distance > radius)
                    {
                        return; // 投影球外的点,置为黑 0,0,0,即默认值
                    }
                    double k;
                    if (distance / radius < 0.001)
                    {
                        k = 1; // k 极小时
                    }
                    else
                    {
                        k = radius / distance * Math.Asin(distance / radius);
                    }

                    // 为了精确快速调整计算顺序,把原始公式在注释给出
                    double x = k * i + (1 - k) * centerX; // 原始公式 k * (i - centerX) + centerX
                    double y = k * j + (1 - k) * centerY; // 原始公式 k * (i - centerX) + centerX
                    if (x >= height || x < 0 || y >= width || y < 0)
                    {
                        return;
                    }
                    for (int channel = 0; channel < 3; channel++)
                    {
                        imgDistorted[i, j, channel] = interpolationFunc(img, x, y, channel);
                    }
                });
            }
            else     // 校正桶形畸变,即对图像做枕形畸变
            {
                System.Threading.Tasks.Parallel.For(0, height * width, index => {
                    int i           = index / width;
                    int j           = index % width;
                    double distance = Math.Sqrt((i - centerX) * (i - centerX) + (j - centerY) * (j - centerY));
                    if (distance > Math.PI / 2 * radius)
                    {
                        return; // 投影球外的点,置为黑 0,0,0,即默认值
                    }
                    double k;
                    if (distance / radius < 0.001)
                    {
                        k = 1; // k 极小时
                    }
                    else
                    {
                        k = Math.Sin(distance / radius) * radius / distance;
                    }

                    // 为了精确快速调整计算顺序,把原始公式在注释给出
                    double x = k * i + (1 - k) * centerX; // 原始公式 k * (i - centerX) + centerX
                    double y = k * j + (1 - k) * centerY; // 原始公式 k * (i - centerX) + centerX
                    if (x >= height || x < 0 || y >= width || y < 0)
                    {
                        return;
                    }
                    for (int channel = 0; channel < 3; channel++)
                    {
                        imgDistorted[i, j, channel] = interpolationFunc(img, x, y, channel);
                    }
                });
            }
            return(imgDistorted);
        }
Example #14
0
        // pointPair[i,0] ~ [i,3] 分别为 控制点x1 控制点y1 目标点x2 目标点y2,控制点:想变成的参考样貌;目标点:待变形图上的坐标
        public static byte[,,] TPSImg(byte[,,] img, InterpolationFunc interpolationFunc,
                                      double[,] pointPair)
        {
            if (pointPair.GetLength(1) != 4)
            {
                return(null); // Error pointPair
            }
            int pointNumber = pointPair.GetLength(0);

            // 构造矩阵Y
            double[,] Y = new double[pointNumber + 3, 2];
            for (var i = 0; i < pointNumber; i++)
            {
                Y[i, 0] = pointPair[i, 2];
                Y[i, 1] = pointPair[i, 3];
            }

            // 构造矩阵L,注意到L为对称阵,赋值时,循环体可以在第二重循环时减半循环量
            double[,] L = new double[pointNumber + 3, pointNumber + 3];
            for (var j = 0; j < pointNumber; j++)
            {
                L[pointNumber, j] = 1;
                L[j, pointNumber] = 1;
            }
            for (var i = pointNumber + 1; i < pointNumber + 3; i++)
            {
                for (var j = 0; j < pointNumber; j++)
                {
                    L[i, j] = pointPair[j, i - pointNumber - 1];
                    L[j, i] = L[i, j];
                }
            }
            for (var i = 0; i < pointNumber; i++)
            {
                for (var j = 0; j <= i; j++)
                {
                    if (j == i)
                    {
                        L[i, j] = 0;
                        break;
                    }
                    L[i, j] = RadialbasisByPoint(pointPair[i, 0], pointPair[i, 1], pointPair[j, 0], pointPair[j, 1]);
                    L[j, i] = L[i, j];
                }
            }
            // 传入高斯消元函数的为引用,会被函数体修改矩阵值,原本应使用
            // double[,] coe = GaussianElimination(L.Clone(), Y.Clone());
            // 但LY不再使用,故为节约耗时,不clone
            double[,] coe = GaussianElimination(L, Y);
            if (coe == null)
            {
                return(null); // 方程无解,返回空图
            }
            int height = img.GetLength(0);
            int width  = img.GetLength(1);

            byte[,,] imgTPSed = new byte[height, width, 3];
            double x;
            double y;

            for (var i = 0; i < height; i++)
            {
                for (var j = 0; j < width; j++)
                {
                    // 先计算 wU之外的项目
                    x = coe[pointNumber, 0] + coe[pointNumber + 1, 0] * i + coe[pointNumber + 2, 0] * j;
                    y = coe[pointNumber, 1] + coe[pointNumber + 1, 1] * i + coe[pointNumber + 2, 1] * j;
                    // 分别计算各wU的结果,按正负号存入数组中,累加时,
                    // 保证xy和新作为加项的wU正负异号
                    // 则整体加法流程充分地让正负相消累计,每一步得到的数的绝对值较小,
                    // 防止double型在位数提高时新引入舍入误差
                    double[,] weightedUArray = new double[pointNumber, 4];
                    double u;
                    double weightedUX;
                    double weightedUY;
                    int    posUXcount = 0;
                    int    negUXcount = 0;
                    int    posUYcount = 0;
                    int    negUYcount = 0;
                    // 计算wU并按正负号存储
                    for (var wCount = 0; wCount < pointNumber; wCount++)
                    {
                        u          = RadialbasisByPoint(i, j, pointPair[wCount, 0], pointPair[wCount, 1]);
                        weightedUX = u * coe[wCount, 0];
                        weightedUY = u * coe[wCount, 1];
                        if (weightedUX > 0)
                        {
                            weightedUArray[posUXcount, 0] = weightedUX;
                            posUXcount++;
                        }
                        else
                        {
                            weightedUArray[negUXcount, 1] = weightedUX;
                            negUXcount++;
                        }

                        if (weightedUY > 0)
                        {
                            weightedUArray[posUYcount, 2] = weightedUY;
                            posUYcount++;
                        }
                        else
                        {
                            weightedUArray[negUYcount, 3] = weightedUY;
                            negUYcount++;
                        }
                    }
                    posUXcount--; posUYcount--; negUXcount--; negUYcount--;
                    // 分正负,尽可能异号累加得到x
                    while (posUXcount >= 0 && negUXcount >= 0)
                    {
                        if (x > 0)
                        {
                            x += weightedUArray[negUXcount, 1];
                            negUXcount--;
                        }
                        else
                        {
                            x += weightedUArray[posUXcount, 0];
                            posUXcount--;
                        }
                    }
                    while (posUXcount >= 0)
                    {
                        x += weightedUArray[posUXcount, 0];
                        posUXcount--;
                    }
                    while (negUXcount >= 0)
                    {
                        x += weightedUArray[negUXcount, 1];
                        negUXcount--;
                    }

                    // 分正负,尽可能异号累加得到y
                    while (posUYcount >= 0 && negUYcount >= 0)
                    {
                        if (y > 0)
                        {
                            y += weightedUArray[negUYcount, 3];
                            negUYcount--;
                        }
                        else
                        {
                            y += weightedUArray[posUYcount, 2];
                            posUYcount--;
                        }
                    }
                    while (posUYcount >= 0)
                    {
                        y += weightedUArray[posUYcount, 2];
                        posUYcount--;
                    }
                    while (negUYcount >= 0)
                    {
                        y += weightedUArray[negUYcount, 3];
                        negUYcount--;
                    }

                    // 得到对应坐标点,到原图中查找像素信息
                    if (x < 0 || x >= height || y < 0 || y > width)
                    {
                        continue;
                    }
                    for (var channel = 0; channel < 3; channel++)
                    {
                        imgTPSed[i, j, channel] = interpolationFunc(img, x, y, channel);
                    }
                }
            }
            return(imgTPSed);
        }
Example #15
0
 /// <summary>
 /// Smoothly adjusts the value of a <see cref="Bindable{TValue}"/> over time.
 /// </summary>
 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
 public static TransformSequence <T> TransformBindableTo <T, TValue>(this T drawable, [NotNull] Bindable <TValue> bindable, TValue newValue, double duration = 0, Easing easing = Easing.None,
                                                                     InterpolationFunc <TValue> interpolationFunc = null)
     where T : ITransformable =>
 drawable.TransformTo(drawable.PopulateTransform(new TransformBindable <TValue, T>(bindable, interpolationFunc), newValue, duration, easing));
Example #16
0
 /// <summary>
 /// Smoothly adjusts the value of a <see cref="Bindable{TValue}"/> over time.
 /// </summary>
 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
 public static TransformSequence <T> TransformBindableTo <T, TValue>(this TransformSequence <T> t, [NotNull] Bindable <TValue> bindable, TValue newValue, double duration = 0, Easing easing = Easing.None,
                                                                     InterpolationFunc <TValue> interpolationFunc = null)
     where T : ITransformable =>
 t.Append(o => o.TransformBindableTo(bindable, newValue, duration, easing, interpolationFunc));