Страницы

Поиск по вопросам

воскресенье, 29 декабря 2019 г.

Три зависимых параметра. Изменение одного влияет и на другие, чтобы сумма оставалась неизменна

#java #математика


Необходимо сделать систему балансирующую три положительных переменных. 

Например, треугольник телосложения из Fallout 4.



Необходимо получить что-то вроде:

class BalanceTriangle() {

    float a = 0.33;
    float b = 0.33;
    float c = 0.33;

    static float sum = 0.99;

    void AddA(float value) {
        ...
    }
}

AddA(0.2f); => [0.53f, 0.23f, 0.23f]


Я пробовал простейший вариант

void AddA() {
    a += value;
    b -= value/2;
    c -= value/2;
}


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

Тогда я попробовал сбрасывать лишнее вычитание на соседнюю переменную:

void AddA() {
    a += value;

    if (b - value > 0) {
        b -= value/2;
    }
    else {
        float rem = (value/2)-b;
        b = 0;
        c -= rem;
    }

    if (c - value > 0) {
        c -= value/2;
    }
    else {
        float rem = (value/2)-b;
        c = 0;
        b -= rem;
    }
}


Но в таком случае сумма по неизвестной причине меняется, а при добавлении операций
на каждую переменную всё это выглядит отвратительно.

Подскажите решение задачи.
    


Ответы

Ответ 1



Раз у Вас уже есть наглядное представление в виде треугольника - то и используйте точку внутри треугольника и её барицентрические координаты В английской вики есть формулы для расчёта этих координат из декартовых

Ответ 2



Нарисуйте по другому картину. Трехмерная система координат. Из центра постройте сферу радиусом 1. Постройте куб со координатами проходящими через (0,0,0) и (1,1,1). Часть сферы которая внутри куба - это и есть поверхность возможных решений. Ну а далее математика из школы. Берете уравнение сферы - одна координата вам известна. То что все координаты положительны - тоже. Неизвестны оставшиеся две координаты. Тут уж есть возможность для творчества - зависит от того как вы захотите распределять изменения между ними. Короче говоря все сведется к решению квадратного уравнения

Ответ 3



Сохранить не только сумму a+b+c, но и пропорции между величинами b и c можно так: Индекс "0" соответствует текущим значениям, "1" - новым. Например, (0.44, 0.33, 0.22) →(0.64, 0.21, 0.14).

Ответ 4



К сожалению, знаний математики не хватило, чтобы реализовать предложенный товарищем MBo вариант, но в итоге всё решилось проще. Сначала я реализовал функцию Set, которая присваивает a определенное значение. Это значение вычитается из необходимой суммы всех параметров, полученное число - остаток, который необходимо распределить между b и c. (rem) Для равномерного изменения я получаю отношение b к оригинальной сумме b+c и аналогично отношение c. (ratio1 и ratio2) Затем из ранее полученного остатка я нахожу необходимую часть, применив отношения. В итоге сумма остаётся неизменна, а части меняются пропорционально оригинальным значениям. static float sum = 0.99; static float maxVal = 0.97; void SetA (float value) { if (value >= 0 && value <= maxValue) { // находим остаток от присваивания, // который должен распределиться между b и c float rem = sum - value; // находим отношение b к сумме b и c, аналогично для c float ratio1 = b/(sum-a); float ratio2 = c/(sum-a); // получаем новые значения пропорциональные оригинальным b = rem * ratio1; c = rem * ratio2; a = value; } } Другие операции на основе этой реализовать не сложно: void AddA (float value) { SetA(a+value); } Результаты: SetA(0.5f); => Sum: 0.99 Params:0.5/0.245/0.245 AddB(0.2f); => Sum: 0.99 Params:0.36577177/0.445/0.17922819 SetC(0.3f); => Sum: 0.99 Params:0.31128675/0.37871325/0.3

Комментариев нет:

Отправить комментарий