Sunday, July 10, 2022

Day 24/100 Turtle3

Day 24/100 Turtle3

Look! An animated Turtle!


This is just a simple improvement for the Turtle graphic program. I had planned on having multi-turtle going, but the truth is, I also wanted to have some kind of font system going. Unfortunately, I'm really tired at the end of the week, and so decided to just implement one easy, yet eye catching feature: Animation.


SVG standard actually does have animation option, but I'm still fuzzy on the details, so for this one, I decided on animating it the hard way: animated GIF.


Fortunately, it's quite easy to do. All I have to do is to generate a series of frames and then use Image Magick convert program to generate the animated GIF. It will also resize the images automatically. This is the command that I use:


time convert -delay 20 -loop 0 Frame*.svg -resize 320x200 FrameAnim.gif


It takes about 30 seconds to do 23 SVGs animation, so not too speedy. However, for small animation picture, that is acceptable. I do wonder why it takes somewhat long to build a 64kB image.


As to the actual code, it is extremely simple. I have already done a simple SVG generator, and all I did was generate SVGs one after the other. There is a line separator marked with desired filename. This is the code that is used to cause the Turtle to write the separator:


  if (!strncmp("WF",s1,2)) {
    printf("WRITE FILE %s\n",s2);
  }


And that's it. If you remember the Day 16/100 SplitCat program, that is the one being used to split the file into separate ones. Quite a convenience. All it takes is a one liner "WF" to write the files. Okay, I also have to set a string for the filename, and incrementing the counter. I considered having it done internal to the Turtle, but in the end decided against it for transparency considerations. Here's the code:


  for (i=40;i<=90;i+=10) {
  for (j=60;j<=120;j+=20) {
    sprintf(FN,"Frame%02d.svg",c++);
    Turtle("WF",FN,0,0);
    Turtle("SC","",0,0);
    DrawCMYK(i,j);
    Turtle("sc","",0,0);
  }}


So, one line to set the string, and another to write the separator. Two lines total. And that is it for this week. Just a simple Turtle enhancement that will hopefully pay dividends down the road.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>

#define MAXENTRY 10000
#define MAXSTR 2560
#define sx0 0
#define sx1 118
#define sy0 0
#define sy1 180
#define PI 3.141528

char Liner[MAXSTR];
char Data[MAXENTRY][MAXSTR];
int numentry;
int Debug=0;

//turtle
char co; //command
int  nu; //Number
int  he; //heading
int  di; //distance
float  an; //angle (rad)
float  tx0,ty0,tx1,ty1; //line
int  pe; //pen color
int  bg; //background color
int mode=0; //0-normal 1-fill
char FontFam[MAXSTR];
int FontSiz;

float map(float x0,float x1, float x2,float y0, float y2) {
  return y0+((x1-x0)*(y2-y0)/(x2-x0)); //y1
}

void SVGHeader() {
  puts("<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" 
style=\"fill-opacity:1; color-rendering:auto; 
color-interpolation:auto; text-rendering:auto; 
stroke:black; stroke-linecap:square; 
stroke-miterlimit:10; shape-rendering:auto; 
stroke-opacity:0.4; fill:black; 
stroke-dasharray:none; font-weight:normal; 
stroke-width:0.25; font-family:'Dialog'; font-style:normal; 
stroke-linejoin:miter; font-size:12px; 
stroke-dashoffset:0; image-rendering:auto;\" 
width=\"128.0mm\" height=\"190.0mm\" 
viewBox=\"0 0 128.0 190.0\" 
xmlns=\"http://www.w3.org/2000/svg\">
<!--Template generated by the Batik Graphics2D SVG Generator-->
<defs id=\"genericDefs\" />
<g>
<line x1=\"10.0\" y1=\"10.0\" x2=\"118.0\" y2=\"10.0\" />
<line x1=\"118.0\" y1=\"10.0\" x2=\"118.0\" y2=\"180.0\" />
<line x1=\"10.0\" y1=\"180.0\" x2=\"118.0\" y2=\"180.0\" />
<line x1=\"10.0\" y1=\"180.0\" x2=\"10.0\" y2=\"10.0\" />
");
}

void SVGFooter() {
puts("
</g>
</svg>
");
}

void SVGDrawLine(float x0,float y0,float x1,float y1) {
  int t;
  if (mode==1) {
    if (pe) {
      printf("L %f,%f ",x1,y1);
    } else {
      printf("M %f,%f ",x1,y1);
    }
  } else if (pe) {
    printf("<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" />\n",
           x0,y0,x1,y1);
  }
}


int Turtle(char s1[], char s2[], int n1, int n2) {
  if (!strncmp("SC",s1,2)) { //Capture SVG
    SVGHeader();
    if (Debug) puts("SVGStart");
  }
  if (!strncmp("sc",s1,2)) { //Close SVG
    SVGFooter();
    if (Debug) puts("SVGEnd");
  }
  if (!strncmp("F",s1,1)) { //forward absolute
    di=n1;
    if (Debug) printf("Forward Absolute %d\n",di);
    an=map(0.0,(float)he,360.0,0,2*PI);
    tx1=tx0+(float)di*sin(an);
    ty1=ty0-(float)di*cos(an);
    SVGDrawLine(tx0,ty0,tx1,ty1);
    tx0=tx1;ty0=ty1;
  }
  if (!strncmp("f",s1,1)) { //forward relative
    di+=n1;
    if (Debug) printf("Forward Relative %d\n",di);
    an=map(0.0,(float)he,360.0,0,2*PI);
    tx1=tx0+(float)di*sin(an);
    ty1=ty0-(float)di*cos(an);
    SVGDrawLine(tx0,ty0,tx1,ty1);
    tx0=tx1;ty0=ty1;
  }
  if (!strncmp("G",s1,1)) { //Goto XY Absolute
    tx1=n1; ty1=n2;
    SVGDrawLine(tx0,ty0,tx1,ty1);
    tx0=tx1;ty0=ty1;
  }
  if (!strncmp("g",s1,1)) { //Goto XY Relative
    tx1=tx0+n1; ty1=ty0+n2;
    SVGDrawLine(tx0,ty0,tx1,ty1);
    tx0=tx1;ty0=ty1;
  }
  if (!strncmp("H",s1,1)) { //Heading Absolute
    he=n1;
    if (Debug) printf("Heading Relative %d\n",he);
  }
  if (!strncmp("h",s1,1)) { //Heading Relative
    he+=n1;
    if (Debug) printf("Heading Relative %d\n",he);
  }
  if (!strncmp("C",s1,1)) { //Color Stroke
    pe=n1;
    if (Debug) printf("Pen color %d\n",pe);
  }
  if (!strncmp("c",s1,1)) { //Color Fill
    bg=n1;
    if (Debug) printf("Background color %d\n",pe);
  }
  if (!strncmp("T",s1,1)) { //Font Fam+Siz
    strcpy(FontFam,s2);
    FontSiz=n1;
  }
  if (!strncmp("t",s1,1)) { //Draw text
    printf("<text x=\"%d\" y=\"%d\" font-family=\"%s\" font-size=\"%d%%\" >"
            ,n1,n2,FontFam,FontSiz);
    printf("%s",s2);
    printf("</text>\n");
  }
  if (!strncmp("M1",s1,2)) { //Mode 1 start
    mode=1;
    if (bg) {
      printf("<path stroke=\"#%6X\" fill-rule=\"evenodd\" fill=\"#%6X\" d=\"\n"
              ,pe,bg);
    } else {
      printf("<path stroke=\"#%6X\" fill-rule=\"evenodd\" fill=\"none\" d=\"\n"
              ,pe,bg);
    }
    printf("M %f,%f ",tx0,ty0);
  }
  if (!strncmp("m1",s1,2)) { //Mode 1 end
    mode=0;
    puts("\" />");
  }
  if (!strncmp("WF",s1,2)) {
    printf("WRITE FILE %s\n",s2);
  }
  return 0;
}

int Init() {
  co=' ';
  nu=0; //Number
  he=0; //heading
  di=0; //distance
  an=0; //angle (deg)
  tx0=59;ty0=90; //line from
  tx1=tx0;ty1=ty0; //line to
  pe=1; //pen
  strcpy(FontFam,"PibotoThin");
  FontSiz=10;
  return 0;
}

void DrawCMYK(int x, int y) {
  Turtle("C","",0x000000,0);
  Turtle("G","",x,y);

  Turtle("C","",0x010101,0);
  Turtle("c","",0x88FFFF,0); //cyan
  Turtle("M1","",0,0);
  Turtle("G","",x,10);
  Turtle("G","",10,10);
  Turtle("G","",10,y);
  Turtle("G","",x,y);
  Turtle("m1","",0,0);
  Turtle("C","",0x010101,0);
  Turtle("c","",0xFF88FF,0); //magenta
  Turtle("M1","",0,0);
  Turtle("G","",x,10);
  Turtle("G","",118,10);
  Turtle("G","",118,y);
  Turtle("G","",x,y);
  Turtle("m1","",0,0);
  Turtle("C","",0x010101,0);
  Turtle("c","",0xFFFF88,0); //yellow
  Turtle("M1","",0,0);
  Turtle("G","",x,180);
  Turtle("G","",10,180);
  Turtle("G","",10,y);
  Turtle("G","",x,y);
  Turtle("m1","",0,0);
  Turtle("C","",0x010101,0);
  Turtle("c","",0x888888,0); //black
  Turtle("M1","",0,0);
  Turtle("G","",x,180);
  Turtle("G","",118,180);
  Turtle("G","",118,y);
  Turtle("G","",x,y);
  Turtle("m1","",0,0);
}

int ProcessData() {
  char Command[MAXSTR];
  char Value[MAXSTR];
  int  Num1=0;
  int  Num2=0;
  int i,j;
  int c=0;
  char FN[MAXSTR];

  for (i=40;i<=90;i+=10) {
  for (j=60;j<=120;j+=20) {
    sprintf(FN,"Frame%02d.svg",c++);
    Turtle("WF",FN,0,0);
    Turtle("SC","",0,0);
    DrawCMYK(i,j);
    Turtle("sc","",0,0);
  }}
  return 0;
}

int main (int argc, char *argv[] ) {
  int n,i;
  Init();
  ProcessData();
  return 0;
}


One last parting thought: I will do something drastic next week. I have been delaying it for some time, and truthfully, I can stay in the same format for some more weeks, but I think it's time for me to incorporate graphical user interface. Since I'm using Raspberry Pi, it's not the easiest thing to do. So, we'll see.


No comments:

Post a Comment