Day 18/100 Turtle 2 (Improved)
Do turtles come in red?
If you remember Day 14, I did a simple turtle graphic program. Well, I revisited the program, and add a bunch of features. A little too much, maybe. It has over 300 lines on it. Quite a program. Yet, it is not complete yet. There's still quite a few capabilities I want to put it in, but it suffices for now.
The code is interesting because of the function Turtle() actually acts like an object. Structurally, it has 4 parameters: 2 strings and 2 numbers. The first string is actually a command for the turtle. Object methods, so to speak. The rest are the parameters, except it's not object oriented. This is just plain old C, instead of C++.
If I want to, I can do it as a graphic library, and I still have an option to do that. Just do it as an abstraction layer, or something. But it's getting complicated, and I'm thinking maybe I should stop here for now, and build some kind of documentation. As it is, it's good enough for some fancy graphic:
A picture of a random tree
Most commands comes in pairs. Usually the point is obvious if you look at the code. The function Turtle() is rather large, but if you look at individual commands, it's actually rather simple for each. Something to remember that doing graphic is usually a library call away. Well, not this one. Here, I simply put out SVG commands, and that's a simple text output.
//TreeMaker with Spark?
if (r>30) {
for (i=3+(rand()%n);i;i--) {
x1=x0+(rand()%r-(r/2));
y1=y0+(rand()%r-(r/3));
Turtle("G","",x0,y0);
Turtle("C","",0x102030,0);
Turtle("G","",x1,y1);
Spark1(x1,y1,n/2,r/2);
}}
Turtle("SC","",0,0);
srand(3333);Turtle("C","",0x010101,0);
Turtle("G","",60,20);Spark1(60,90,32,75);
srand(6666);Turtle("C","",0,0);
Turtle("G","",60,20);Spark1(60,90,32,70);
srand(9999);Turtle("C","",0,0);
Turtle("G","",60,20);Spark1(60,90,32,60);
srand(18100);Turtle("C","",0,0);
Turtle("G","",60,20);Spark2(60,90,32,60);
Turtle("sc","",0,0);
This is the main code for drawing the tree. It uses 2 Spark functions. Originally, I used a recursive function, but then I added color, and well, there you go. I'd say the tree looks good enough for something that is random.
I also added some SVG capabilities, such as Fonts. I'm thinking that maybe I should just change the name from Turtle to SVG Library. Oh, well, that is something to do in the future. I may as well do it, too. It's no longer a turtle graphic program when I eliminate turn left and turn right. Those has been replaced with Heading(relative) and Heading(absolute).
Furthermore, I changed the program so that it can handle multiple character command. So, with that, it has greatly expanded the capability of taking in numerous commands. BTW, most commands comes in upper case and lower case versions.
SC: prints out SVG file header
sc: prints out SVG file footer
F - n1: Forward, absolute distance
f - n1: forward, relative distance
G - n1,n2: Goto XY, absolute
g - n1,n2: Goto XY, relative
H - n1: Heading, absolute (0-360)
h - n1: Heading, relative
C - n1: Stroke (pen) color. 0 for pen up
c - n1: Fill color. 0 for "none"
T - s2,n1: Set Font, Font name, size
t - s2,n1,n2: Draw Text. Text,X,Y
M1 - EvenOdd Fill mode. Uses background color
m1 - disable fill mode.
These command set is enough to allow for some sophisticated graphic. I was even able to include the SVG code in my blog! So, that's good.
#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 Absolute %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("\" />");
}
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;
}
int ProcessData() {
char Command[MAXSTR];
char Value[MAXSTR];
int Num1=0;
int Num2=0;
int i,j;
Turtle("C","",0x112233,0);
Turtle("c","",0xCCBBAA,0);
Turtle("SC","",0,0);
// Turtle("M1","",0,0);
for (i=10;i<170;i+=5) {
Turtle("C","",0,0);
Turtle("G","",10,i);
Turtle("C","",0x102030,0);
Turtle("G","",113,i);
}
// Turtle("m1","",0,0);
Turtle("T","FreeMono",40,0);
Turtle("t","FreeMono 40",15,20);
Turtle("t","ABCDEFGHIKLMNOPQRSTUVWXYZ",15,25);
Turtle("t","abcdefghijklmnopqrstuvwxyz",15,30);
Turtle("T","FreeSans",40,0);
Turtle("t","FreeSans 40",15,35);
Turtle("t","ABCDEFGHIKLMNOPQRSTUVWXYZ",15,40);
Turtle("t","abcdefghijklmnopqrstuvwxyz",15,45);
Turtle("T","FreeSerif",40,0);
Turtle("t","FreeSerif 40",15,50);
Turtle("t","ABCDEFGHIKLMNOPQRSTUVWXYZ",15,55);
Turtle("t","abcdefghijklmnopqrstuvwxyz",15,60);
Turtle("T","Quicksand Light",50,0);
Turtle("t","Quicksand Light 50",15,70);
Turtle("t","The quick brown fox jumps over the",15,75);
Turtle("t","ABCDEFGHIKLMNOPQRSTUVWXYZ",15,80);
Turtle("t","abcdefghijklmnopqrstuvwxyz",15,85);
Turtle("T","Quicksand Light",40,0);
Turtle("t","Quicksand Light 40",15,95);
Turtle("t","The quick brown fox jumps over the lazy dog",15,100);
Turtle("t","ABCDEFGHIKLMNOPQRSTUVWXYZ",15,105);
Turtle("t","abcdefghijklmnopqrstuvwxyz",15,110);
Turtle("T","Quicksand Light",30,0);
Turtle("t","Quicksand Light 30",15,120);
Turtle("t","The quick brown fox jumps over the lazy dog",15,125);
Turtle("t","ABCDEFGHIKLMNOPQRSTUVWXYZ",15,130);
Turtle("t","abcdefghijklmnopqrstuvwxyz",15,135);
Turtle("T","Quicksand Light",20,0);
Turtle("t","Quicksand Light 20",15,145);
Turtle("t","The quick brown fox jumps over the lazy dog",15,150);
Turtle("t","ABCDEFGHIKLMNOPQRSTUVWXYZ",15,155);
Turtle("t","abcdefghijklmnopqrstuvwxyz",15,160);
Turtle("sc","",0,0);
return 0;
}
int Spark1(int x0,int y0, int n, int r) {
int i;
int x1,y1;
if (r>30) {
for (i=3+(rand()%n);i;i--) {
x1=x0+(rand()%r-(r/2));
y1=y0+(rand()%r-(r/3));
Turtle("G","",x0,y0);
Turtle("C","",0x102030,0);
Turtle("G","",x1,y1);
Spark1(x1,y1,n/2,r/2);
}}
if (r<=30) {
Turtle("c","",0x99FF99,0);
Turtle("M1","",0,0);
for (i=3+(rand()%n);i;i--) {
x1=x0+(rand()%r-(r/4));
y1=y0+(rand()%r-(r/3));
Turtle("G","",x1,y1);
}
Turtle("m1","",0,0);
}
return 0;
}
int Spark2(int x0,int y0, int n, int r) {
int i;
int x1,y1;
if (r>15) {
for (i=3+(rand()%n);i;i--) {
x1=x0+(rand()%r-(r/2));
y1=y0+(rand()%r-(r/3));
Turtle("G","",x0,y0);
Turtle("C","",0x102030,0);
Turtle("G","",x1,y1);
Spark2(x1,y1,n/2,r/2);
}}
if (r<=15) {
Turtle("c","",0x338833,0);
Turtle("M1","",0,0);
for (i=3+(rand()%n);i;i--) {
x1=x0+(rand()%r-(r/4));
y1=y0+(rand()%r-(r/3));
Turtle("G","",x1,y1);
}
Turtle("m1","",0,0);
}
return 0;
}
int main (int argc, char *argv[] ) {
int n,i;
Init();
// ProcessData();
//TreeMaker with Spark?
Turtle("SC","",0,0);
srand(3333);Turtle("C","",0x010101,0);
Turtle("G","",60,20);Spark1(60,90,32,75);
srand(6666);Turtle("C","",0,0);
Turtle("G","",60,20);Spark1(60,90,32,70);
srand(9999);Turtle("C","",0,0);
Turtle("G","",60,20);Spark1(60,90,32,60);
srand(18100);Turtle("C","",0,0);
Turtle("G","",60,20);Spark2(60,90,32,60);
Turtle("sc","",0,0);
return 0;
}
One more thing: Should I actually just make this an SVG library with Turtle layer?
No comments:
Post a Comment