Выглядит как простая графическая задача

StackOverflow https://stackoverflow.com/questions/1040437

  •  22-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

Это было полезно?

Решение

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

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

 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-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], извините за первоначальную ошибку.

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top