在2D 3 x 3网格中旋转对角线-需要旋转矩阵吗? [英] Rotate a diagonal line in a 2D 3 x 3 grid - rotation matrix needed?

查看:94
本文介绍了在2D 3 x 3网格中旋转对角线-需要旋转矩阵吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在建立一个用于绘画ASCII艺术的图书馆。给定我有一个3 x 3的图,其中每个点代表一个像素,一条线从点 0,0 开始,对角线变为 2,2 (左下角到右上角)。



如果我画画布,它看起来像这样:

  2 /点:2,0 2,1 2,2 
1 / 1,0 1,1 2,1
0 / 0,0 1,0 2,0
0 1 2

我现在想建立一个算法,可以将线顺时针向右旋转,所以如果我应用该行的算法,结果应为:

  2分:2,0 2,1 2,2 
1 1,0 1,1 2,1
0 _ _ _ 0,0 1,0 2,0
0 1 2

基本上,该线向右旋转45度,从而形成一条水平线。



我想我需要一个旋转矩阵,如



此处45deg预览:





您可以看到45度旋转是一个问题,因为它不是1:1映射的,所以某些单元格将映射到多个单元格中。对于固定分辨率,您可以手动进行一些1:1映射,但是我怀疑是否可以通过算法轻松实现动态分辨率。



是的,您仅使用(3x3)映射,其中可以旋转45度,但是您的问题仍然存在,因为当您映射单个像素时,某些像素将被再次复制,并且如果考虑到您正在查看的字符,它将看起来很糟糕。



如果将所有这些放在一起,我宁愿只使用90deg旋转,除非您获得图像的矢量表示...



通过LUT可以加快字符旋转



[Edit1] 45度旋转



我给它一些教导,找出45度旋转的解决方案。您必须使用其他旋转内核。不绕圆旋转,而是按圆周的1/8围绕正方形旋转。为了更好地理解这里的一个小例子:

  // r = 1 
0 1 2 7 0 1
7 3-> 6 2
6 5 4 5 4 3

// r = 2
0 1 2 3 4 EF 0 1 2
F 5 D 3
E 6-> C 4
D 7 B 5
CBA 9 8 A 9 8 7 6

这是1:1映射,因此没有问题。 C ++中的代码如下:

  // --------- -------------------------------------------------- ---------------- 
void rot45cw()
{
int x0,y0,ax,ay,ad,bx,by,bd, a,b,i,r,rs;
char tmp [xs] [ys],q;
//旋转内核4个方向
const int dx [4] = {0,-1,0,+ 1};
const int dy [4] = {-1,0,+ 1,0};
//旋转中心
x0 = xs / 2;
y0 = ys / 2;
//复制图片到tmp
(ay = 0; ay< ys; ay ++)
for(ax = 0; ax< xs; ax ++)
tmp [ax] [ay] = pic [ax] [ay];
//旋转所有螺钉以填充整个地图
rs = xs;如果(rs< ys)rs = ys; (r = 1; r< rs; r ++)的

{
ax = x0 + r; ay = y0 + r; ad = 0; a = 0; //开始位置a
bx = x0; by = y0 + r; bd = 3; b = r; //开始位置b
for(i = 8 * r; i> 0; i--)//处理一个螺丝
{
//获取并转换处理后的字符
if((ax = 0)&&(ax< xs)&&(ay> = 0)&(ay&y; ys))
if((bx> = 0)& ;&(bx< xs)&&(by = 0)&&(byys))
{
q = tmp [ax] [ay];
如果(q =='-’)q ='\\';
else if(q ==’\\’)q =’|’;
else if(q ==’|’)q =’/’;
else if(q ==’/’)q =’-';
pic [bx] [by] = q;
}
//更新位置
ax + = dx [ad]; bx + = dx [bd];
ay + = dy [ad]; by + = dy [bd];
//更新方向
a ++;如果(a> = r + r){a = 0; ad =(ad + 1)& 3; }
b ++;如果(b> = r + r){b = 0; bd =(bd + 1)& 3; }
}
}
//获取并转换旋转中心
if((x0> = 0)&&(x0< xs)&&(y0> ; = 0)&((y0< ys))
{
q = pic [x0] [y0];
如果(q =='-’)q ='\\';
else if(q ==’\\’)q =’|’;
else if(q ==’|’)q =’/’;
else if(q ==’/’)q =’-';
pic [x0] [y0] = q;
}
}
// ---------------------------------- -----------------------------------------
void rot45ccw()
{
int x0,y0,ax,ay,ad,bx,by,bd,a,b,i,r,rs;
char tmp [xs] [ys],q;
//旋转内核4个方向
const int dx [4] = {0,-1,0,+ 1};
const int dy [4] = {-1,0,+ 1,0};
//旋转中心
x0 = xs / 2;
y0 = ys / 2;
//复制图片到tmp
(ay = 0; ay< ys; ay ++)
for(ax = 0; ax< xs; ax ++)
tmp [ax] [ay] = pic [ax] [ay];
//旋转所有螺钉以填充整个地图
rs = xs;如果(rs< ys)rs = ys; (r = 1; r< rs; r ++)的

{
ax = x0 + r; ay = y0 + r; ad = 0; a = 0; //开始位置a
bx = x0; by = y0 + r; bd = 3; b = r; //开始位置b
for(i = 8 * r; i> 0; i--)//处理一个螺丝
{
//获取并转换处理后的字符
if((ax = 0)&&(ax< xs)&&(ay&= 0;)&(ay&y; ys))
if((bx> = 0)& ;&(bx< xs)&&(by = 0)&&(by< ys))
{
q = tmp [bx] [by];
如果(q ==’-’)q =’/’;
else if(q ==’/’)q =’|’;
else if(q ==’|’)q =’\\’;
,否则(q =='\\')q ='-';
pic [ax] [ay] = q;
}
//更新位置
ax + = dx [ad]; bx + = dx [bd];
ay + = dy [ad]; by + = dy [bd];
//更新方向
a ++;如果(a> = r + r){a = 0; ad =(ad + 1)& 3; }
b ++;如果(b> = r + r){b = 0; bd =(bd + 1)& 3; }
}
}
//如果((x0> = 0)&&(x0< xs)&&(y0> ; = 0)&((y0< ys))
{
q = pic [x0] [y0];
如果(q ==’-’)q =’/’;
else if(q ==’/’)q =’|’;
else if(q ==’|’)q =’\\’;
,否则(q =='\\')q ='-';
pic [x0] [y0] = q;
}
}
// ---------------------------------- -----------------------------------------

dx,dy 表仅类似于 sin cos 。最后是预览:




I'm building a library for drawing ASCII art. Given I have a 3 x 3 graph, where each point represents a pixel, a line starts at point 0,0 and goes diagonal to 2,2 (bottom left point to top right point).

If I draw the canvas, it looks like this:

2   /      Points: 2,0  2,1  2,2
1  /               1,0  1,1  2,1
0 /                0,0  1,0  2,0
  0 1 2

I now want to build an algorithm that can rotate the line clockwise to the right, so if I apply the algorithm to the line, the result should be:

2         Points: 2,0  2,1  2,2
1                 1,0  1,1  2,1
0 _ _ _           0,0  1,0  2,0
  0 1 2

So basically the line is rotated by 45 degrees to the right, resulting in an horizontal line.

I think I need a rotation matrix for this as described in http://mathworld.wolfram.com/RotationMatrix.html but the math is a bit above my head.

Anyone has a simple explanation on how this would work, given my 2D coordinate system, maybe in pseudo code?

解决方案

It does not matter if you use the matrices or not. Here simple C++ example without matrices using all what I mention in my comments:

//---------------------------------------------------------------------------
const int xs=32;
const int ys=32;
char pic[xs][ys];
//---------------------------------------------------------------------------
void cls();
void rot45cw();
void rot90cw();
//---------------------------------------------------------------------------
void cls()
    {
    int x,y;
    // clear screen
    for (y=0;y<ys;y++)
     for (x=0;x<xs;x++)
      pic[x][y]=' ';
    // add diagonal line for testing
    for (x=xs/2;(x<xs)&&(x<ys);x++) pic[x][x]='\\';
    }
//---------------------------------------------------------------------------
void rot45cw()
    {
    int x,y,ix,iy,x0,y0;
    float fx,fy,a,c,s;
    char tmp[xs][ys],q;
    a=-45.0*M_PI/180.0; // rotation angle [rad]
    x0=xs/2;            // center of rotation
    y0=ys/2;
    c=cos(a); s=sin(a);
    // copy pic to tmp
    for (y=0;y<ys;y++)
     for (x=0;x<xs;x++)
      tmp[x][y]=pic[x][y];
    // rotate
    for (y=0;y<ys;y++)
     for (x=0;x<xs;x++)
        {
        // offset so (0,0) is center of rotation
        fx=x-x0;
        fy=y-y0;
        // rotate (fx,fy) by ang
        ix=float((fx*c)-(fy*s));
        iy=float((fx*s)+(fy*c));
        // offset back
        ix+=x0;
        iy+=y0;
        // transform tmp to pic
        if ((ix>=0)&&(ix<xs)&&(iy>=0)&&(iy<ys)) q=tmp[ix][iy]; else q=' ';
             if (q=='/') q='\\';
        else if (q=='\\') q='/';
        else if (q=='-') q='|';
        else if (q=='|') q='-';
        pic[x][y]=q;
        }
    }
//---------------------------------------------------------------------------
void rot90cw()
    {
    int x,y,ix,iy,x0,y0;
    char tmp[xs][ys],q;
    // center of rotation
    x0=xs/2;
    y0=ys/2;
    // copy pic to tmp
    for (y=0;y<ys;y++)
     for (x=0;x<xs;x++)
      tmp[x][y]=pic[x][y];
    // rotate
    for (y=0;y<ys;y++)
     for (x=0;x<xs;x++)
        {
        // rotate
        iy=x0-(x-x0);
        ix=y0+(y-y0);
        // transform tmp to pic
        if ((ix>=0)&&(ix<xs)&&(iy>=0)&&(iy<ys)) q=tmp[ix][iy]; else q=' ';
             if (q=='-') q='\\';
        else if (q=='\\') q='|';
        else if (q=='|') q='/';
        else if (q=='/') q='-';
        pic[x][y]=q;
        }
    }
//---------------------------------------------------------------------------

and usage:

// clear and add diagonal line for testing once:
cls();
// and this do in some timer or whatever:
//rot45cw();
rot90cw();

Here 90deg preview:

Here 45deg preview:

As you can see 45deg rotation is a problem as it is not 1:1 mapping so some cells will map into more than one cell. For fixed resolution you can do some 1:1 mapping manually but I doubt it would be easily implemented algorithmically for dynamic resolution.

Yes You are using just (3x3) maps where the 45 deg rotation is possible but your problem persists because when you map individual pixels then some will be copied again and if you take into account you are viewing characters it would look bad.

If I put all together I would rather use 90deg rotations only unless you got vector representation of the image...

The character rotation can be speeded up with LUTs

[Edit1] 45 degree rotation

I give it a bit more taught and find out solution for the 45 degree rotations. You must use different rotation kernel. Not rotate around circles but arround squares by 1/8 of circumference. To better understand here small example:

// r=1
0 1 2    7 0 1
7   3 -> 6   2
6 5 4    5 4 3

// r=2
0 1 2 3 4    E F 0 1 2
F       5    D       3
E       6 -> C       4
D       7    B       5
C B A 9 8    A 9 8 7 6

This is 1:1 mapping so no problems with that. The code in C++ looks like this:

//---------------------------------------------------------------------------
void rot45cw()
    {
    int x0,y0,ax,ay,ad,bx,by,bd,a,b,i,r,rs;
    char tmp[xs][ys],q;
    // rotation kernel 4 directions
    const int dx[4]={ 0,-1, 0,+1};
    const int dy[4]={-1, 0,+1, 0};
    // center of rotation
    x0=xs/2;
    y0=ys/2;
    // copy pic to tmp
    for (ay=0;ay<ys;ay++)
     for (ax=0;ax<xs;ax++)
      tmp[ax][ay]=pic[ax][ay];
    // rotate all "screws" to fill entire map
    rs=xs; if (rs<ys) rs=ys;
    for (r=1;r<rs;r++)
        {
        ax=x0+r; ay=y0+r; ad=0; a=0; // start position a
        bx=x0  ; by=y0+r; bd=3; b=r; // start position b
        for (i=8*r;i>0;i--)          // process one screw
            {
            // fetch and convert processed character
            if ((ax>=0)&&(ax<xs)&&(ay>=0)&&(ay<ys))
             if ((bx>=0)&&(bx<xs)&&(by>=0)&&(by<ys))
                {
                q=tmp[ax][ay];
                     if (q=='-') q='\\';
                else if (q=='\\') q='|';
                else if (q=='|') q='/';
                else if (q=='/') q='-';
                pic[bx][by]=q;
                }
            // update position
            ax+=dx[ad]; bx+=dx[bd];
            ay+=dy[ad]; by+=dy[bd];
            // update direction
            a++; if (a>=r+r) { a=0; ad=(ad+1)&3; }
            b++; if (b>=r+r) { b=0; bd=(bd+1)&3; }
            }
        }
    // fetch and convert center of rotation
    if ((x0>=0)&&(x0<xs)&&(y0>=0)&&(y0<ys))
        {
        q=pic[x0][y0];
             if (q=='-') q='\\';
        else if (q=='\\') q='|';
        else if (q=='|') q='/';
        else if (q=='/') q='-';
        pic[x0][y0]=q;
        }
    }
//---------------------------------------------------------------------------
void rot45ccw()
    {
    int x0,y0,ax,ay,ad,bx,by,bd,a,b,i,r,rs;
    char tmp[xs][ys],q;
    // rotation kernel 4 directions
    const int dx[4]={ 0,-1, 0,+1};
    const int dy[4]={-1, 0,+1, 0};
    // center of rotation
    x0=xs/2;
    y0=ys/2;
    // copy pic to tmp
    for (ay=0;ay<ys;ay++)
     for (ax=0;ax<xs;ax++)
      tmp[ax][ay]=pic[ax][ay];
    // rotate all "screws" to fill entire map
    rs=xs; if (rs<ys) rs=ys;
    for (r=1;r<rs;r++)
        {
        ax=x0+r; ay=y0+r; ad=0; a=0; // start position a
        bx=x0  ; by=y0+r; bd=3; b=r; // start position b
        for (i=8*r;i>0;i--)          // process one screw
            {
            // fetch and convert processed character
            if ((ax>=0)&&(ax<xs)&&(ay>=0)&&(ay<ys))
             if ((bx>=0)&&(bx<xs)&&(by>=0)&&(by<ys))
                {
                q=tmp[bx][by];
                     if (q=='-') q='/';
                else if (q=='/') q='|';
                else if (q=='|') q='\\';
                else if (q=='\\') q='-';
                pic[ax][ay]=q;
                }
            // update position
            ax+=dx[ad]; bx+=dx[bd];
            ay+=dy[ad]; by+=dy[bd];
            // update direction
            a++; if (a>=r+r) { a=0; ad=(ad+1)&3; }
            b++; if (b>=r+r) { b=0; bd=(bd+1)&3; }
            }
        }
    // fetch and convert center of rotation
    if ((x0>=0)&&(x0<xs)&&(y0>=0)&&(y0<ys))
        {
        q=pic[x0][y0];
             if (q=='-') q='/';
        else if (q=='/') q='|';
        else if (q=='|') q='\\';
        else if (q=='\\') q='-';
        pic[x0][y0]=q;
        }
    }
//---------------------------------------------------------------------------

The dx,dy tables are simply analogy to sin and cos. Finally here is the preview:

but of coarse if you rotate square around its center it would not be as you expected !!! Here CCW example:

这篇关于在2D 3 x 3网格中旋转对角线-需要旋转矩阵吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆