#c #arrays #algorithm #loops #trigonometry
#c #массивы #алгоритм #циклы #тригонометрия
Вопрос:
Я использую следующий код для поворота битовой маски (упакованного 2d-массива). Честно говоря, я не очень хорошо разбираюсь в используемом алгоритме, я скопировал и модифицировал код поворота из библиотеки pygame (где он использовался для поворота поверхностей). Благодаря реализации bitmask
я могу значительно ускорить это вращение, изменив внутренний цикл. Я имею в виду, что вместо того, чтобы делать, foreach y { foreach x { ... } }
мне нужно делать foreach x { foreach y { ... } }
. У меня возникли проблемы с обращением цикла, потому что тригонометрия должна быть адаптирована таким образом, которого я в данный момент не вижу.
Вот код:
typedef struct bitmask {
int w,h;
BITMASK_W bits[1];
} bitmask_t;
bitmask_t* bitmask_rotate(const bitmask_t *mask, float angle) {
bitmask_t *newmask = NULL;
double radangle, sangle, cangle;
int isin, icos;
double cx, cy, sx, sy;
int x, y, ax, ay, xd, yd, dx, dy;
int nxmax, nymax, xmaxval, ymaxval;
radangle = angle * DEG_TO_RAD;
sangle = sin(radangle);
cangle = cos(radangle);
isin = (int)(sangle * 65536);
icos = (int)(cangle * 65536);
x = mask->w;
y = mask->h;
cx = cangle*x;
cy = cangle*y;
sx = sangle*x;
sy = sangle*y;
nxmax = (int) (MAX (MAX (MAX (fabs (cx sy), fabs (cx - sy)), fabs (-cx sy)), fabs (-cx - sy)));
nymax = (int) (MAX (MAX (MAX (fabs (sx cy), fabs (sx - cy)), fabs (-sx cy)), fabs (-sx - cy)));
newmask = bitmask_create(nxmax, nymax, 0);
if (!newmask) return NULL;
cy = newmask->h / 2;
xd = ((mask->w - newmask->w) << 15);
yd = ((mask->h - newmask->h) << 15);
ax = ((newmask->w) << 15) - (int)(cangle * ((newmask->w - 1) << 15));
ay = ((newmask->h) << 15) - (int)(sangle * ((newmask->w - 1) << 15));
xmaxval = ((mask->w) << 16) - 1;
ymaxval = ((mask->h) << 16) - 1;
for (y = 0; y < newmask->h; y ) {
dx = (ax (isin * (cy - y))) xd;
dy = (ay - (icos * (cy - y))) yd;
for (x = 0; x < newmask->w; x ) {
if (!(dx < 0 || dy < 0 || dx > xmaxval || dy > ymaxval)) {
if (bitmask_getbit(mask, dx >> 16, dy >> 16)) {
bitmask_setbit(newmask, x, y);
}
}
dx = icos;
dy = isin;
}
}
return newmask;
}
Прежде чем люди спросят «что вы пробовали?», я зациклил вращающиеся матрицы в Википедии, и я мог видеть, что там происходит, и как они реализовали это в этом алгоритме (предварительно вычисляют начальное значение dx
и dy
, а затем увеличивают на icos
и isin
), но сдвиги в битах и параметры, которые я не понимаю ( ax
например), затрудняют мне следовать.
Ответ №1:
for (x = 0; x < newmask->w; x ) {
dx = (ax (isin * cy icos * x)) xd;
dy = (ay - (icos * cy - isin * x)) yd;
for (y = 0; y < newmask->h; y ) {
if (!(dx < 0 || dy < 0 || dx > xmaxval || dy > ymaxval)) {
if (bitmask_getbit(mask, dx >> 16, dy >> 16)) {
bitmask_setbit(newmask, x, y);
}
}
dx -= isin;
dy = icos;
}
}
Комментарии:
1. Я пробовал это, и это, к сожалению, неверно. Возможно, было бы полезно знать, что угол увеличивается против часовой стрелки, а начало координат находится слева вверху.
2. На самом деле это правильно! Присмотревшись повнимательнее, я заметил, что вы использовали
dx
вместоx
. Я возьму на себя смелость отредактировать ваш ответ и 1 и тоже приму его. Спасибо!3. О, да. Я сосредоточился на знаках и пропустил эту опечатку… Спасибо за исправление.