Say I have a bool[][], and I want to rotate it by 37 degrees. I am aware that the tra开发者_如何学Cnsformation wouldn't always be perfect, and that's okay. I've ready plenty of answers on here similar to my question, but the only solutions I've found only solve the problem for 90 degree increments.
The best way is to loop over the destination locations and for each of them read the correct source location. If you try the other way around (i.e. looping on source and writing on destination) you will end up with gaps.
The rotation formula is simple...
source_x = dest_x * c + dest_y * s + x0
source_y = dest_x * -s + dest_y * c + y0
where c
is the cosine of the angle, s
is the sine of the angle and x0, y0
are used to correctly translate the rotated image. In psedudocode
for y = 0, 1, ... dest_height
for x = 0, 1, ... dest_width
src_x = c*x + s*y + x0
src_y = -s*x + c*y + y0
copy from source[src_y][src_x] to dest[y][x]
x0, y0
can be computed so that the source center will end up in the destination center by
x0 = src_width/2 - c*dest_width/2 - s*dest_height/2
y0 = src_height/2 - c*dest_height/2 + s*dest_width/2
If instead of just using c = cos(angle)
and s = sin(angle)
you scale both of them with a factor k
the resulting image will be rotated and zoomed around the center.
Note also that the formulas are bilinear in x
and y
; this means that you can use the full formula for the complete value for the first pixel of a row and then just do src_x += c
and src_y -= s
for each element of the same row because that is what happens when moving from x
to x+1
.
Note also that depending on source and destination size it may be that the computed source element is not available because out of the image. In this case there are several normally used options
- Write a fixed value (e.g.
false
) - Don't write that destination cell
- Do a "clamping" limiting both coordinates to the maximum allowed before reading
- Do a "tiling" by normalizing coordinates using the modulo operator
- Do a mirrored continuation by normalizing with TWICE the size and taking the symmetrical value
2*size-value
if normalized value is bigger than the size
Where x, y are your Cartesian coordinates and R is your rotation angle:
newx = x * cos(R) - y * sin(R)
newy = x * sin(R) + y * cos(R)
Assuming you are rotating a bitmap, I'd first look at using an imaging framework (e.g. System.Drawing) to achieve what you want. Say, take your bools, turn it into a 1-bpp bitmap, draw it rotated, and read it back out.
If that's not what you want, you can either use the rotation provided by wberry and apply to each bool, or if performance is at a premium, write your own texturized rectangle rasterizer. To do the latter, look at some old graphics programming textbooks on how to texture map arbitrary 2D polygons.
Unless you really, really want to do this yourself, consider using something like AForge -- more specifically AForge.Imaging.Filters.RotateBicubic. This routine handles 24bpp and 8bpp images, so you'd need to rotate the RGB content (as a 24bpp image) separately from the alpha channel (as an 8bpp image).
精彩评论