Выглядит как простая графическая задача - PullRequest
3 голосов
/ 24 июня 2009

В настоящее время у меня есть элемент управления, к которому мне нужно добавить средство для применения различной остроты (или чувствительности). Проблема лучше всего проиллюстрирована в виде изображения:

График http://img87.imageshack.us/img87/7886/control.png

Как видите, у меня есть оси X и Y, у которых обе произвольные пределы 100 - этого должно хватить для этого объяснения. В настоящее время моим элементом управления является красная линия (линейное поведение), но я хотел бы добавить возможность для других 3 кривых (или более), то есть, если элемент управления более чувствительный, то параметр будет игнорировать линейный параметр и перейти к из трех строк. Начальная точка всегда будет 0, а конечная точка всегда будет 100.

Я знаю, что экспонента слишком крута, но, похоже, не могу найти путь вперед. Любые предложения, пожалуйста?

Ответы [ 6 ]

3 голосов
/ 25 июня 2009

Кривые, которые вы иллюстрировали, очень похожи на гамма-коррекция кривые. Идея заключается в том, что минимум и максимум диапазона остаются такими же, как у входа, но середина согнута, как у вас на графиках (я могу отметить, что не дуга окружности, которую вы получите из косинуса реализации).

Графически это выглядит так:

alt text
(источник: wikimedia.org )

Итак, с этим как вдохновение, вот математика ...

Если ваши значения x варьировались от 0 до 1, функция довольно проста:

y = f(x, gamma) = x ^ gamma

Добавьте значение xmax для масштабирования (то есть x = от 0 до 100), и функция становится:

y = f(x, gamma) = ((x / xmax) ^ gamma) * xmax

или альтернативно:

y = f(x, gamma) = (x ^ gamma) / (xmax ^ (gamma - 1))

Вы можете сделать еще один шаг, если хотите добавить ненулевой xmin.

Когда гамма равна 1, линия всегда идеально линейна (у = х). Если х меньше 1, ваша кривая изгибается вверх. Если х больше 1, ваша кривая наклоняется вниз. Обратное значение гаммы преобразует значение обратно в исходное (x = f (y, 1 / g) = f (f (x, g), 1 / g).

Просто настройте значение гаммы в соответствии со своим вкусом и потребностями применения. Поскольку вы хотите предоставить пользователю несколько вариантов «повышения чувствительности», вы можете предложить своим пользователям выбор в линейном масштабе, скажем, от -4 (наименее чувствительный) до 0 (без изменений) до 4 (наиболее чувствительный). ), и масштабируйте свои внутренние значения гаммы с помощью степенной функции. Другими словами, предоставьте пользователю выбор (-4, -3, -2, -1, 0, 1, 2, 3, 4), но переведите его в значения гаммы (5.06, 3.38, 2.25, 1.50, 1.00 0,67, 0,44, 0,30, 0,20).

Кодирование в C # может выглядеть примерно так:

public class SensitivityAdjuster {
    public SensitivityAdjuster() { }
    public SensitivityAdjuster(int level) {
        SetSensitivityLevel(level);
    }
    private double _Gamma = 1.0;
    public void SetSensitivityLevel(int level) {
        _Gamma = Math.Pow(1.5, level);
    }
    public double Adjust(double x) {
        return (Math.Pow((x / 100), _Gamma) * 100);
    }
}

Чтобы использовать его, создайте новый SensitivityAdjuster, установите уровень чувствительности в соответствии с предпочтениями пользователя (либо с помощью конструктора или метода, и от -4 до 4, вероятно, будут разумными значениями уровня), и вызовите Adjust (x), чтобы получить скорректированное выходное значение. Если вам нужен более широкий или более узкий диапазон разумных уровней, вы должны уменьшить или увеличить это значение 1,5 в методе SetSensitivityLevels. И, конечно, 100 представляет ваше максимальное значение х.

1 голос
/ 25 июня 2009

Я предлагаю простую формулу, которая (я считаю) отражает ваше требование. Чтобы получить полный «четверть круга», что является вашим крайним случаем, вы должны использовать (1-cos((x*pi)/(2*100)))*100.

Я предлагаю вам взять средневзвешенное значение между y = x и y = (1-cos ((x * pi) / (2 * 100))) * 100. Например, чтобы иметь очень близкое к линейному (99% линейное), возьмите:

y = 0.99*x + 0.01*[(1-cos((x*pi)/(2*100)))*100]

Или, в более общем смысле, скажем, что уровень линейности равен L, и он находится в интервале [0, 1], ваша формула будет:

y = L*x + (1-L)*[(1-cos((x*pi)/(2*100)))*100]

РЕДАКТИРОВАТЬ: я изменил cos(x/100) на cos((x*pi)/(2*100)), потому что для того, чтобы результат cos был в диапазоне [1,0], X должен быть в диапазоне [0, pi / 2], а не [0,1 ], извините за первоначальную ошибку.

0 голосов
/ 25 июня 2009

Для подобных задач я часто получаю несколько точек на кривой и добавляю их в программу подбора кривой. Там их куча. Вот один с 7-дневной бесплатной пробной версией.

Я многому научился, пробуя разные модели. Часто вы можете получить довольно простое выражение, чтобы приблизиться к вашей кривой.

0 голосов
/ 25 июня 2009

Я голосую за общую идею Ракса Олгуда с одной модификацией:

y = alpha * x + (1-alpha)*(f(x/100)*100)

альтернативный текст http://www4c.wolframalpha.com/Calculate/MSP/MSP4501967d41e1aga1b3i00004bdeci2b6be2a59b?MSPStoreType=image/gif&s=6

где f (0) = 0, f (1) = 1, f (x) является суперлинейным, но я не знаю, откуда взялась эта идея "четверть круга" или почему 1-cos (x) будет хороший выбор.

Я бы предложил f (x) = x k , где k = 2, 3, 4, 5, независимо от того, что дает желаемый коэффициент крутизны для & alpha = 0. Выберите значение для k как фиксированное число, затем измените & alpha; выбрать конкретную кривую.

0 голосов
/ 24 июня 2009

График y = x^p для x от 0 до 1 будет делать то, что вы хотите, когда вы меняете p от 1 (что даст красную линию) вверх. По мере увеличения p кривая будет «выталкиваться» все больше и больше. p не обязательно должно быть целым числом.

(Вам нужно масштабировать, чтобы получить от 0 до 100, но я уверен, что вы можете решить это)

0 голосов
/ 24 июня 2009

Возможно, вы ищете что-то вроде полиномиальной интерполяции . Квадратичная / кубическая / квартальная интерполяция должна дать вам кривые, которые вы показываете в вопросе. Различия между тремя кривыми, которые вы показываете, вероятно, могут быть достигнуты только путем корректировки коэффициентов (которые косвенно определяют крутизну).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...