2016-03-19 17 views
0

Я пишу программу, которая будет вращать прямоугольную призму вокруг точки. Он обрабатывает вращение с помощью трех методов вращения, каждый из которых управляет вращением вокруг одной оси (X, Y и Z). Вот кодJava: Вращения и 3D-искажения

public void spinZ(Spin spin) { 

    if (x == 0 && y == 0) { 
     return; 
    } 
    double mag = Math.sqrt(x * x + y * y); 
    double pxr = Math.atan(y/x); 
    x = Math.cos(spin.zr + pxr) * mag; 
    y = Math.sin(spin.zr + pxr) * mag; 
} 
public void spinY(Spin spin) { 

    if (z == 0 && x == 0) { 
     return; 
    } 
    double mag = Math.sqrt(x * x + z * z); 
    double pxr = Math.atan(z/x); 
    x = Math.cos(spin.yr + pxr) * mag; 
    z = Math.sin(spin.yr + pxr) * mag; 
} 
public void spinX(Spin spin) { 

    if (z == 0 && y == 0) { 
     return; 
    } 
    double mag = Math.sqrt(y * y + z * z); 
    double pxr = Math.atan(z/y); 
    y = Math.cos(spin.xr + pxr) * mag; 
    z = Math.sin(spin.xr + pxr) * mag; 
} 

public void addSpin(Spin spin) { 

    spinY(spin); 
    spinX(spin); 
    spinZ(spin); 

} 

Спин является бесполезным класс, который хранит три двойников (которые вращение). Эти методы в основном преобразуют вращения в 2D-векторы (как я храню точки) и вращают их как таковые. Первый оператор if гарантирует, что 2D-векторы не являются величиной 0. Им разрешено, но в этом случае нет необходимости выполнять вычисления вращения. Другая часть просто обрабатывает триггер. Нижний метод просто связывает все вместе и позволяет мне быстро менять порядок вращения (потому что порядок должен и должен влиять на окончательное вращение).

Проблема заключается не в отдельных поворотах, а в том, когда они все объединяются. Я могу легко получить одно вращение вокруг одной оси для работы без искажения прямоугольной призмы. Когда я собираю их все вместе, например, если вы должны вызвать addSpin().

При вызове первой очереди призмы искажаются, когда вращение включает в себя вращение Y (если y-составляющая вращения равна нулю, а поворот вокруг оси y не должен происходить, то никаких искажений не происходит). На самом деле, если spinY() вызывается в любое время, но в последствии происходит искажение куба.

То же самое происходит и с spinZ(). Если spinZ() называется последним, куб не будет деформирован. Однако spinX() может идти куда угодно и не вызывать искажения.

Итак, вопрос в том, есть ли проблема с тем, как я двигаюсь по поворотам? Другой вопрос заключается в том, что, хотя все вращения не могут быть охвачены поворотами вдоль осей X и Y или любой другой пары различных осей (например, X и Z, или Y и Z), могут ли эти три группы собирать все вращения? Чтобы уточнить, могут ли вращения, которые не могут быть достигнуты с помощью набора оборотов вокруг осей X и Y, могут быть выполнены с помощью поворота вокруг осей X и Z или осей Y и Z?

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

Это некоторые параллельные вычисления, которые по-прежнему приводят к искажениям.

public void spinZ(Spin spin) { 

    double c = Math.cos(spin.yr); 
    double s = Math.sin(spin.yr); 
    double xp = x*c - y*s; 
    double yp = y*s + x*c; 
    x = xp; 
    y = yp; 
} 
public void spinY(Spin spin) { 

    double c = Math.cos(spin.yr); 
    double s = Math.sin(spin.yr); 
    double zp = z*c - x*s; 
    double xp = z*s + x*c; 
    x = xp; 
    z = zp; 
} 
public void spinX(Spin spin) { 

    double c = Math.cos(spin.yr); 
    double s = Math.sin(spin.yr); 
    double yp = y*c - z*s; 
    double zp = z*c + y*s; 
    y = yp; 
    z = zp; 
} 

ответ

1

Ваши чеки для вещей, как

x == 0 

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

Почему они не нужны? Поскольку следующее выполняет ротацию в очистителя (численно стабильный) мода:

double c = Math.cos(spin.yr); 
double s = Math.cos(spin.yr); 
double zp = z*c - x*s; 
double xp = z*s + x*c; 
x = xp; 
z = zp; 

Конечно, мой пример предполагает рассматривать вращение у с правой рукой ориентации, но из вашего образца кода вы, кажется, рассматривая его как левая. В любом случае, статья wikipedia на Rotation matrix объясняет математику.

+0

Причина, по которой я проверяю значение 0, заключается не столько в том, что когда x и z равны, мне не нужны вычисления. Это то, что когда вы деляете 0 на 0 в java, вы получаете NaN, что заставляет задуматься. И это было бы правостороннее против левостороннего вращения, вызывающее искажения?Я бы так не подумал, но я мог ошибаться ... –

+0

Нет, я бы предположил, что искажения происходят потому, что вы вычисляете радиальный угол, не различая (+, +) и (-, -), ни между (+, -) и (-, +) координатных пар. Я знаю, почему вы проверяете нуль, но, как я уже сказал, если вы используете вычисление матрицы вращения вместо изменения координат, у вас будут более стабильные вычисления без необходимости условий ветвления. –

+0

Хорошо, я заменил ваши методы расчета вместо моего (модифицируя каждый из них в соответствии с матрицами вращения) и протестировал его. Призма все еще искажалась. Я вставлю адаптированные методы, чтобы убедиться, что триггер проверяет. –