| |
Axel Account closed
Registered: Apr 2006 Posts: 42 |
Point rotation
How can I rotate point by fixed axis? how calculate new x and new y coordinates in assembler? |
|
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Same as in any other CPU or language. What exactly are you asking? How it works mathematically, or how to implement it efficiently in assembler or perhaps both?
|
| |
HCL
Registered: Feb 2003 Posts: 728 |
x = x0 * cos(a) + y0 * sin(a)
y = y0 * cos(a) - x0 * sin(a)
..causes rotation around one axis. So, basically you need a sin/cos, and a mul. The rest is on http://codebase64.org/doku.php |
| |
Axel Account closed
Registered: Apr 2006 Posts: 42 |
Ok thanks, but I need to rotate many points using one angle around one axis How to do this efficiently? |
| |
ready.
Registered: Feb 2003 Posts: 441 |
look at http://noname.c64.org/csdb/release/?id=41457, the dot plot part (flower part, I still have the final flower part to release......)
There I rotate many points around around the XY origin, it is a 2-D XY rotation.
The basic technique used there is, as said:
x = x0 * cos(a) + y0 * sin(a)
y = y0 * cos(a) - x0 * sin(a)
so, one cos look up table and one sin look up table. Then an efficient multiplication routine:
a*b = f(a+b) - f(a-b), f(x) = x^2/4
Look here: fixed point multiplication
or codebase, as said.
PM me if you want some code examples.
Ready.
|
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
if everything is fixed, and only the angle is changing you can pretty much precalculate everything. (one sine & cosine table for each radius used) |
| |
yago
Registered: May 2002 Posts: 333 |
If the angle is fixed, you can rotate without using cosine, sinus or multiplication.
NEW X = OLD X - epsilon * OLD Y
NEW Y = OLD Y + epsilon * NEW(!) X
http://www.inwap.com/pdp10/hbaker/hakmem/hacks.html#item149
epsilon can be power of 2, to change speed of rotation, use different epsilons.
this is used for example in Stars and Stabbers
PS: For this to work, you must used signed bytes, though. |
| |
Jetboy
Registered: Jul 2006 Posts: 337 |
How about using complex numbers? That will give you rotation and scaling in one pass with only addition and multiplication used. |
| |
Graham Account closed
Registered: Dec 2002 Posts: 990 |
Which only gives you an advantage in notation but not in 6502 code. |
| |
Slammer
Registered: Feb 2004 Posts: 416 |
Quote: Ok thanks, but I need to rotate many points using one angle around one axis How to do this efficiently?
If you really mean ONE axis so you dont want to rotate the rotated point around another axis afterwards, then you could represent the points as a length(l) and an angle(pa). Now you can reduce the calculation to:
x = l*cos(a+pa)
y = l*sin(a+pa)
where a is the angle you want to rotate
|
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Or you do it like the dot-plot parts out there. Assume integer based input coords.
Per frame look up the cos and sin value of your angle.
c[0] = cos(a)
s[0] = sin(a)
Add these by themselfes a couple of times to get *2, *3, *4 etc to whatever you need depending on your input set size and store into the rest of the c[] and s[] arrays.
Now compute the a coord X,Y simple do:
x = c[X] + s[Y]
y = c[Y] - s[X]
So, for instance, if you know u have input coords ranging from 0..31 in both directions u need to do about 64 adds per frame to calculate the c[] and s[] arrays. Then the rest is simple additions.
|
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
Jackie, brilliant. but why not precompute the coords into polar. giving:
x = c[X]
y = s[Y]
and while we're at it, why not precompute the *2 *3 *4 tables aswell.
|
| |
doynax Account closed
Registered: Oct 2004 Posts: 212 |
Quote: Jackie, brilliant. but why not precompute the coords into polar. giving:
x = c[X]
y = s[Y]
and while we're at it, why not precompute the *2 *3 *4 tables aswell.
Sure, that works too. It just eats a bunch of memory.
The most straightforward method is to avoid recomputing anything each frame, as you suggested, and instead just keep a full set of scaled sine and cosine arrays with double the normal period in memory.
That way the load's address specifies both the point's distance (e.g. the table number) and relative angle (the table offset.) With an index register to animate the rotation.
The obvious drawback here is that you won't be able to animate the scaling. Well, that and fact that it eats quite a bit of memory.
Perhaps the most interesting possibility of this setup is that it allows you to precalculate significant portions of the pixel addressing calculations, though come to think of it with you might not actually save any cycles when working with a clever char layout. Plus that approach would waste *even more* memory and prevent the usual space-saving trick of overlapping the horizontal (cosine) and vertical (sine) tables. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
well, Axel wasnt asking for scaling, and wasting memory is no problem as long as it speeds up the routine :) I would waste happily 16k for tables in such a demopart. Regarding speed/scaling/mem usage Jack's method is the best indeed.
precomputing addies made me think, the routine would look like this for a 32x25 screen, first part setting dot&presetting dot clear code, 2nd part is clearing the dot.
lda YtabLo,x
sta $fe
sta clrspeed+wherever
lda YtabHi,x
sta $ff
sta Clrspeed+wherever
ldy Xoffset,x
sty Clrsped+wherever
lda ($fe),y
ora Mask,x
sta ($fe),y
...
...
clrspeed
ldy #Xoffset
sta bitmap,y
...
...
edit: oh my its bugged, and keeping Y zero might be faster, I'll leave it to you :) |
| |
doynax Account closed
Registered: Oct 2004 Posts: 212 |
I was thinking something more along these lines:plot lda sincos_hi(a,s),x
sta $ff
sta clear+1
ldy sincos_lo(a,s),x
sty clear+2
lda sincos_bit(a,s),x
; ora ($fe),y
sta ($fe),y
.
.
.
clear sta $ffff
With, say, 128 angles and 48 scales this would eat 36k of memory for the tables alone.
A nice point is that for static objects you could figure out ahead of time which plots might potentially intersect and thus avoid the ORA in the majority of the cases. That is if you wanted to bother with masking to begin with.
For the last 127 plots or so you could store the full address in a unique zeropage location and reuse it directly in the clearing code, saving something like three cycles per plot.
In the end you might squeeze 500 or so plots out of it, but the size of the plot code alone would almost kill you. And in the end it would look pretty lame compared to a comparable 3D plotter in which you'd get full 3D rotation and scaling for half that number of vertices.
But perhaps it might pay off if you wanted to plot into some byzantine sprite-based screen layout, with complex clip regions and color-effects based on the screen coordinates. |
| |
Axel Account closed
Registered: Apr 2006 Posts: 42 |
Thanks for your help :). Nice ideas, now I will try to do it |