-
[RESOLVED] Rotation
I have an array that contains the state of certain cells. It looks like this.
Code:
5
4
3 * * * *
y 2 * * * *
1 * * * *
0 * * * *
0 1 2 3 4 5
x
I am trying to rotate the array using this formula:
x' = (x * Cos deg.) - (y * Sin deg.)
y' = (x * Sin deg.) + y * (Cos deg.)
The code (VB .Net) uses Math.Cos & Math.Sin which produce double results. I think my problem happens when I convert the results to integer. Am I missing something?
-
Re: Rotation
You did not mention a problem.
That rotation equation is valid for arbitrary angles and arbitrary x, y values. Obviously, for a finite grid you will get into trouble; you can never execute the rotation exactly over an arbitrary angle (perhaps there are some angles like 45 or 30 degrees that will work exactly, but not all). Only in the limit that your cell size goes to zero (== continuous, infinite cells) will you be able to represent the rotation exactly, but of course that is a limit you cannot practically take.
I would tell you to simply round the values down or up, but I'm sure you are already doing that by converting to an integer so evidently that doesn't work as you expected (though you didn't tell us what happens).
Perhaps you can try something 'clever' like rounding the x values 'to the left' (== down) and the y values up or down when the angle is between 0 and 180 degrees. Otherwise, the cells appear underneath the x-axis and you would round the x values 'to the right' (== up). This is just something I thought of and probably does not work at all.
-
Re: Rotation
One thing that might be tripping you up is that you've written your formula in degrees, while the .NET trig functions expect arguments in radians. To convert 50 degrees to radians, multiply by pi/180, i.e. 50 degrees = 50*pi/180 radians = 0.872 radians. All other angles are similar.
But yeah, we haven't actually been told a problem, so maybe that's not it at all.
-
Re: Rotation
vb c#
[guess]If you are transforming each cell from the source array to the target array you will find the end result is nearly always full of holes (edit: as nick is saying above). Do it backwards, transform each cell in the target array back to the source and you can guarantee all cells will be filled. [/guess]
You can also work in scaled integers if you wish. It's considerably faster than converting every single cell calculation from Double to Integer. Choose a scale that gives enough decimal precision without overflowing.
Code:
const int SCL = 0x10000;
int ICos0 = (int)(Math.Cos(angle) * (double)SCL);
int ISin0 = (int)(Math.Sin(angle) * (double)SCL);
x1 = (x * ICos0 - y * ISin0) / SCL;
y1 = (x * ISin0 + y * ICos0) / SCL;
It's C# but .net is .net.
-
Re: Rotation
Thanks everyone! Making the angle 90 degrees and converting to radians sure made a big difference.
The Game of Life has taken over mine ;) I have learned a lot about graphics in the last couple of weeks.
Code:
'real close...
' x' = (x * Cos deg.) - (y * Sin deg.)
' y' = (x * Sin deg.) + y * (Cos deg.)
SetUndo() 'set undo
CutPBsel(False) 'cut the selection, (copy to PBselCopy then delete it)
If PBselCopy.Count <= 1 Then Exit Sub
Dim d As Double = degrees * (Math.PI / 180) 'Thanks to jemidiah@vbforums for this nugget
Dim x, y As Double, rect As Rectangle = New Rectangle(0, 0, 0, 0)
Dim xc, yc As Integer 'the centers
'calculate centers
For z As Integer = 0 To PBselCopy.Count - 1
xc += PBselCopy(z).X
yc += PBselCopy(z).Y
Next
xc = xc \ PBselCopy.Count
yc = yc \ PBselCopy.Count
For z As Integer = 0 To PBselCopy.Count - 1
'make relative to center
PBselCopy(z).X = PBselCopy(z).X - xc
PBselCopy(z).Y = PBselCopy(z).Y - yc
'rotate
x = (PBselCopy(z).X * Math.Cos(d)) - (PBselCopy(z).Y * Math.Sin(d))
y = (PBselCopy(z).X * Math.Sin(d)) + (PBselCopy(z).Y * Math.Cos(d))
'make relative to center
PBselCopy(z).X = CInt(x) + xc
PBselCopy(z).Y = CInt(y) + yc
'set the state
zCellUniverse.State(PBselCopy(z).X, PBselCopy(z).Y) = PBselCopy(z).State
'new selection rectange
If rect.IsEmpty Then
rect = New Rectangle(PBselCopy(z).X * BlockSize, PBselCopy(z).Y * BlockSize, _
BlockSize, BlockSize)
Else
rect = Rectangle.Union(rect, New Rectangle(PBselCopy(z).X * BlockSize, PBselCopy(z).Y * BlockSize, _
BlockSize, BlockSize))
End If
Next
-
Re: [RESOLVED] Rotation
A 90 degree rotation can be done much more simply than using the rotation matrix and trig functions. If speed is at all an issue, at the least you can evaluate Math.Cos(d) and Math.Sin(d) beforehand and plug them in directly. I don't know if the .NET compiler is smart enough to know that those functions don't have side effects and that it can optimize them out.