### Author Topic: Turtle graphics  (Read 227 times)

#### raymw

• Newbie
• Posts: 39
##### Turtle graphics
« on: 2022-02-12, 19:33:31 »
I was around when Logo and turtle graphics were first popular, but more or less ignored them. Recently I saw a Utube video (numberphile) where it was explained hor turtle graphics could produce SierpiĆski Triangles, and I thought that maybe using AngelCAD could possibly do something similar but in 3d, for 3d printing. I've not used AngelCAD for sometime, and it is a struggle getting back into the flow, so to speak. I ran some simple tests, and decided that I would not be able to plot a meaningful triangle using my PC, in any reasonable amount of time.

However, with significant help from Carsten, I managed to produce something based loosely on turtle graphics, and I've put the code below. It sort of can print various patterned tubes, with or without a base. ( a vase, if you like), but if you water tight, you will need to adjust the various values. However, for the variables I've set, it fails after about 1250 iterations (i.e. in my code 'range' set to more than 1250) , however that may be a limitation in my particular PC. I started by generating a tube, then decided to add a base, and give a few other options, which can readily alter the appearance of the whole object. If the angle is not a factor of 360, then you will get a sort of spiral shape, as in the values I've shown. There are still a number of features that could be added - I've just added a print out of the approximate height, but with a bit of effort that could be more precisely calculated, and that value used to calculate 'range' .

Code: [Select]
` double rfd = PI/180;  //rads from degreesvoid settings (thing &out it){    it.le = 20;  // length of rod    it.w = 2;    // width of rod    it.h = 2;    // height of rod     it.rot = false; // rotate rods by 45 degree, to remove horizontal overhangs    it.range = 1250;   // number of rods    it.a = 50;    // angle between rods    it.b = it.h/(360/it.a);  // vertical angle    it.base = true; // false if base not needed     it.round = false; // set to true if wanted rounded adges instead of square (diamete =w)    it.blob = 0;  // diameter of blob at corners (0 to ignore)        ////////////////////////////////////    it.bang=0;    it.cang=0;return;}   class thing{   double le, w, h, a, b, blob, bang, cang = 0;      int range = 0;   bool base, round, rot = true;}   solid@ part(thing it){                   solid@ stroke = cuboid(it.le,it.w,it.h,false);                      if (it.rot == true)           {                 @stroke = rotate_x(rad:rfd*45)* stroke; // angle to make printable           }    if (it.round==true)    {                  @stroke  = rotate_y(rad:PI/2)*cylinder(it.le,it.w/2);                   }       return stroke;}        solid@ ball(double blob){  return sphere(r:blob/2);}         solid@ draw( thing it, pos3d@ now, pos3d@ &out last){   solid@ ans=      translate(now.x(),now.y(),now.z())*      rotate_z(rad:rfd*it.cang)*      part(it);   // calc 'last' for next 'now'        @last = now + pos3d(cos(rfd*it.cang)*it.le,sin(rfd*it.cang)*it.le,it.bang );   // put sphere at corner if needed       if (it.blob >0 )       {                     @ans =ans +  translate(last.x(),last.y(),last.z())*ball(it.blob);        }   return ans;} void main(){    thing it;    settings(it); //get values    pos3d@ now = {0,0,0};    pos3d@ last= {it.le,0,0};    array <pos2d@> points;    solid@ obj;         @obj = part(it);  // this is to become the set of lines     int count=0;           while( count < it.range )       {                  it.bang=0;  // flatten bottom ( b, vertical angle =0) and make polygon              if (count <= 360/it.a)              {               points.push_back(pos2d(last.x(),last.y()));              }                                if (count>((360/it.a)))                    {                 it.bang=it.bang+it.b;  // now add vertical angle                  }                    if (count>=it.range-(360/it.a)-1)  // to give flat top                        {                     it.bang=0;  // vertical angle 0 for last few                     }           it.cang=it.cang+it.a;              @now = last;              @obj = obj+draw(it,now,last);        count++;      }                  if (it.round==true)           {           @obj= translate(0,0,it.w/2)*obj;           }               if (it.base==true)  // make solid base              {               polygon@ solid_base = polygon (points);               @obj=obj + linear_extrude(solid_base,height:it.h);              }         // assume no overlap              cout<< "aproximate height " << (it.range /(360/it.a))*it.h << endl;      obj.write_xcsg(GetInputFullPath(),secant_tolerance:-1.0);} `
I've put the values you can change at the top of the program listing, in the settings function, but of course, you can do what you like with the rest of it. If you want to play with it, then set range to 590, to get a quick fstl, which will give you an idea of the patterns you can get.

#### raymw

• Newbie
• Posts: 39
##### Re: Turtle graphics
« Reply #1 on: 2022-03-07, 18:26:37 »
I've added a bit more complexity to the original code. It can produce interesting stl files 3d prints, or can, if the values are not correct, produce equally interesting errors.
With careful choice of parameters you can create a multi spiral sided pot, with a screw-on lid, for example. I have just added a facility to reverse the direction of the spiral at various heights. The values I have in the example code works, produces a water tight pot, other values may throw errors, at the moment it is almost trial and error. to choose workable values. I will add some images, if possible.
Code: [Select]
`// turtle tubedouble rfd = PI/180;  //rads from degreesvoid settings (thing &out it){    it.le = 20;  // length of rod      it.w = 1.5;    // width of rod    it.h = 1.5;    // height of rod     it.rot = false; // rotate rectangular rods by 45 degree, to remove horizontal overhangs    it.range = 200;   // number of rods     it.a =61;    // angle between rods   // it.b = 0.7*it.h/(360/it.a);  // vertical angle     it.b = 0.5*it.h/(360/it.a); // smaller vertical angle to allow for reversal of direction.    it.base = true;// false if base not needed     it.flat = false ; // true for flat base    it.round = true; // set to true if wanted rounded adges instead of square (diamete =w)    it.blob = 2;  // diameter of blob at corners (0 to ignore)    it.rev = false;  // set true if you want spiral (if any) reversed    it.cut = 0 ; // if a positive value, it cuts off the top of 'cylinder', at cut.height    it.dir =24 ;  // if a positive value, it reverses direction every dir number of rods    it.ar = 59 ;  // 'reverse direction' angle    ////////////////////////////////////   return;}   class thing{   double le, w, h, a, b, blob, bang, cang, cut, dir, dirc, ar = 0;      int range = 0;   bool base, round, rot, flat, rev = true;}   solid@ part(thing it){                   solid@ stroke = translate(it.le/2,0,0)*cuboid(it.le,it.w,it.h,true);                      if (it.rot == true)           {                 @stroke = rotate_x(rad:rfd*45)* stroke; // angle to make 3d printable - 45 deg overhangs           }    if (it.round==true)    {                  @stroke  = rotate_y (rad:PI/2)*cylinder(it.le,it.w/2);                   }       return stroke;}        solid@ ball(double blob){  return sphere(r:blob/2);}         solid@ draw( thing it, pos3d@ now, pos3d@ &out last){   solid@ ans=      translate(now.x(),now.y(),now.z())*      rotate_z(rad:rfd*it.cang)*       part(it);   // calc 'last' for next 'now'        @last = now + pos3d(cos(rfd*it.cang)*it.le,sin(rfd*it.cang)*it.le,it.bang );   // put sphere at corner if needed       if (it.blob >0 )       {                     @ans =ans +  translate(last.x(),last.y(),last.z())*ball(it.blob);        }   return ans;} void main(){    thing it;    settings(it); //get values    pos3d@ now = {0,0,0};    pos3d@ last= {it.le,0,0};    array <pos2d@> points;    solid@ obj;    double tempa = it.a;    if (it.base == true)  {     it.flat=true;  }          @obj = part(it);  // this is to become the set of lines     int count=0;           while( count < it.range )       {                  it.bang=0;  // flatten bottom ( b, vertical angle =0) and make polygon                          if (it.flat==true)             {               if (count <= 360/it.a)               {                                          points.push_back(pos2d(last.x(),last.y()));               }                                if (count>((360/it.a)))                    {                       it.bang=it.bang+it.b;  // now add vertical angle                  }                    if (count>=it.range-(360/it.a)-1)  // to give flat top                       {                          it.bang=0;  // vertical angle 0 for last few                    }            }                        if (it.flat == false)            {               it.bang=it.bang+it.b;            }              it.cang=it.cang+it.a;              @now = last;              @obj = obj+draw(it,now,last);              // change direction              if (it.dir >=1)              {                  it.dirc=it.dirc+1;                                if (it.dir== it.dirc)                    {                       tempa=it.a;                       it.a=it.ar;                       it.ar=tempa;                       it.dirc=0;                    }              }                     count++;      }                  if (it.rot==true)           {            // get rotaton position of base             @obj= translate(0,0,(sqrt((it.w *it.w) + (it.h*it.h))*0.5)-it.w/2)*obj;                        }           @obj= translate(0,0,it.w/2)*obj;                       if (it.base==true)  // make solid base              {               polygon@ solid_base = polygon (points);               @obj=obj + linear_extrude(solid_base,height:it.h);                if (it.rev == true)                {                  @obj= mirror(1,0,0)*obj;                }                    if (it.cut>0)  // cut off top using 500 cube centred                   {                     @obj = obj-translate(0,0,it.cut+250)*cube(500,true);                   }     }         // assume no overlap              cout<< "aproximate height " << (it.range /(360/it.a))*it.h << endl;             obj.write_xcsg(GetInputFullPath(),secant_tolerance:0.0010);}       `