2016-11-01 4 views
1

저는 ASCII 아트 그리기 라이브러리를 만들고 있습니다. 각 포인트가 픽셀을 나타내는 3 x 3 그래프가있는 경우 라인은 0,0 지점에서 시작하여 2,2 (대개 왼쪽 상단에서 오른쪽 상단 지점까지) 대각선으로 이동합니다. 나는 캔버스를 그리면2D 3 x 3 격자 - 회전 행렬에서 대각선을 회전 시키시겠습니까?

, 그것은 다음과 같습니다

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 

지금 오른쪽 라인 시계 방향으로 회전 할 수있는 알고리즘을 구축하려는, 그래서 라인 알고리즘을 적용 할 경우 결과는 다음과 같아야합니다 :

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 

그래서 기본적으로 줄이 오른쪽으로 45도 회전되어 수평선이 생깁니다.

http://mathworld.wolfram.com/RotationMatrix.html에 설명 된대로 회전 행렬이 필요하다고 생각하지만 수학은 머리 위 비트입니다.

누구나 내 2D 좌표계가 주어지면 의사 코드로 어떻게 작동하는지 간단하게 설명 할 수 있습니까?

+0

는 항상 기원에 대한 ASCII 아트를 회전하고 있는가? –

+0

@TimBiegeleisen 당신은 회전의 중심점을 의미합니까? – Max

+0

예, 이것이 제가 묻는 것입니다. –

답변

1

매트릭스를 사용하는지 여부는 중요하지 않습니다. 여기에 간단한 C++ 내 의견에 언급 무엇을 모두 사용하여 매트릭스없이 예 :

//--------------------------------------------------------------------------- 
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; 
     } 
    } 
//--------------------------------------------------------------------------- 

및 사용 :

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

90DEG 미리보기 :

다음

90cw

45deg 미리보기 :

45cw

위에서 볼 수 있듯이 1 : 1 매핑이 아니기 때문에 45도 회전이 문제가되므로 일부 셀이 둘 이상의 셀에 매핑됩니다. 고정 해상도의 경우 수동으로 1 : 1 매핑을 할 수 있지만 동적 해상도의 경우 알고리즘 적으로 쉽게 구현할 수 있을지는 의문입니다.

예 개별 픽셀을 매핑 할 때 일부는 다시 복사되기 때문에 45도 회전이 가능하지만 문제는 지속되는 단지 (3x3) 맵만 사용하고 일부는 다시 복사되고 고려하면 문자가 보입니다. .

나는

문자 회전

이 LUT를

[EDIT1]

45 학위를 가속화 할 수 있습니다 ... 이미지의 벡터 표현을 가지고하지 않는 한 나는 오히려 90DEG 회전을 사용하는 것이 모두 함께 넣어 경우 rotation

나는 그것을 더 많이 가르쳐주고 45도 회전을위한 해결책을 찾는다. 다른 회전 커널을 사용해야합니다. 원주의 1/8로 원을 그리지 않고 정사각형으로 회전하지 않습니다. 여기에 작은 예제를 더 잘 이해하기 위해 :

이것은 1 : 1 매핑이므로 문제가 없습니다.C++의 코드는 다음과 같습니다

//--------------------------------------------------------------------------- 
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; 
     } 
    } 
//--------------------------------------------------------------------------- 

dx,dy 테이블 sincos 단순히 비유입니다. 마지막으로 여기에 미리보기는 다음과 같습니다

rot45cw square kernel

하지만 굵은의 당신이 그 중심 주위에 사각형 회전 경우 예상대로되지 않을 것! 여기 CCW 예 :

rectangle

+0

고마워요! 이것은 매우 좋은 요약입니다, 나는 90도 회전으로 갈 것이고, 그것은 나의 작은 애완 동물 프로젝트에 훨씬 더 쉬울 것 같다. ASCII 아트로 이미지를 변환하는 예제는 genuis이며, 저도 해보고 싶습니다! – Max

+0

@Max가 도움이되기를 기뻐합니다 ... 만약 당신이 rot90ccw를 만들고 싶다면 다른 좌표 대신에 ... – Spektre

+0

하하는 매우 멋집니다! 고맙습니다. :) 그것을 살펴보고 필요한 코드를 수정하려고합니다. ASCII 그래픽으로 놀고있는 것 같습니다. – Max