如何将二维数组旋转到任意程度?

假设我有一个bool [] [],我想将它旋转37度。 我知道转型并不总是完美的,那没关系。 我已经准备好了很多类似于我的问题的答案,但我发现的唯一解决方案只能解决90度增量的问题。

最好的方法是遍历目标位置,并为每个位置读取正确的源位置。 如果你尝试相反的方式(即在源上循环并在目的地上书写),你最终会有差距。

旋转公式很简单……

source_x = dest_x * c + dest_y * s + x0 source_y = dest_x * -s + dest_y * c + y0 

其中c是角度的余弦, s是角度的正弦, x0, y0用于正确平移旋转的图像。 在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以便源中心最终到达目的地中心

  x0 = src_width/2 - c*dest_width/2 - s*dest_height/2 y0 = src_height/2 - c*dest_height/2 + s*dest_width/2 

如果不是仅仅使用c = cos(angle)s = sin(angle)而是使用因子k对它们进行缩放,结果图像将围绕中心旋转和缩放。

另请注意,公式在xy是双线性的; 这意味着您可以使用完整的公式来获取行的第一个像素的完整值,然后对同一行的每个元素执行src_x += csrc_y -= s ,因为这是从x移动到x+1

另请注意,根据源和目标大小,计算的源元素可能不可用,因为图像外。 在这种情况下,有几种常用选项

  1. 写一个固定值(例如false
  2. 不要写那个目标单元格
  3. 进行“夹紧”,将坐标限制在读数前允许的最大值
  4. 通过使用模运算符标准化坐标来进行“平铺”

其中x,y是笛卡尔坐标,R是你的旋转角度:

 newx = x * cos(R) - y * sin(R) newy = x * sin(R) + y * cos(R) 

假设您正在旋转位图,我首先考虑使用成像框架(例如System.Drawing)来实现您想要的效果。 比如说,拿起你的bool,把它变成一个1-bpp的位图,把它旋转,然后把它读出来。

如果那不是您想要的,您可以使用wberry提供的旋转并应用于每个bool,或者如果性能非常高,请编写自己的纹理化矩形光栅化器。 要做到后者,请查看一些关于如何纹理映射任意2D多边形的旧图形编程教科书。

除非你真的,真的想自己这样做,考虑使用像AForge这样的东西 – 更具体地说是AForge.Imaging.Filters.RotateBicubic 。 此例程处理24bpp和8bpp图像,因此您需要将Alpha内容(作为24bpp图像)与Alpha通道分开旋转(作为8bpp图像)。