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