"Turtle Graphics" in Batch files!

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
Aacini
Expert
Posts: 1675
Joined: 06 Dec 2011 22:15
Location: México City, México

"Turtle Graphics" in Batch files!

#1 Post by Aacini » 06 Sep 2015 20:15

Turtle Graphics is a method to draw graphics introduced by Logo programming language more than 40 years ago that have a series of virtues, particularly in the areas of teaching graphics and/or programming. You may review a very simple introduction to Turtle Graphics in Logo at this site. The Turtle Graphics feature that I most like is its ability to draw certain complex graphics (like spirals or recursive curves) in a much simpler way when compared vs. traditional methods that use cartesian coordinates.

Turtle Graphics requires a simpler interface than other graphics schemes, so its implementation is easier. I developed a series of subroutines for Batch files that provides the equivalent graphics capabilities of Logo programming language; I called this work "Batch Turtle Graphics" or BTG. The method to show the graphics is based on my previous development that used HTML5 canvas tag to draw graphics in a .HTA window:

Aacini wrote:Batch-BGI: a *standard* graphics library for Batch files.
http://www.dostips.com/forum/viewtopic.php?f=3&t=6625

You may review implementation details of Batch Turtle Graphics on that topic; you must copy and paste the link.

Code: Select all

@if (@CodeSection == @Batch) @then


@echo off

:: TurtleGraphics.bat: Turtle Graphics in Batch files
:: Written by Antonio Perez Ayala aka Aacini
:: Turtle Graphics reference: http://www.logointerpreter.com/logo-reference/turtle-graphics-canvas.php
:: Canvas reference: http://www.w3schools.com/tags/ref_canvas.asp

setlocal EnableDelayedExpansion
if "%~1" equ "TurtleGraphics" goto %1

cls
echo/
echo                  Batch Turtle Graphics, by Antonio Perez Ayala
echo/
echo call :newWindow t x y      Open a new graphics window as specified; the Turtle
echo call :nw title maxX maxY   is placed at center of window, pointing upwards.
echo/
echo call :penDown              Start a new drawing at current Turtle position;
echo call :pd                   you *must* put the pen down to start drawing.
echo/
echo call :forward expr         Moves the Turtle forward expr pixels;
echo call :fd expr              negative values go backwards.
echo/
echo call :back expr            Moves the Turtle backward expr pixels;
echo call :bk expr              negative values go forward.
echo/
echo call :right expr           Rotates the Turtle expr degrees clockwise;
echo call :rt expr              negative values rotate counterclockwise.
echo/
echo call :left expr            Rotates the Turtle expr degrees counterclockwise;
echo call :lt expr              negative values rotate clockwise.
echo/
echo call :penUp                End the current drawing and show it in the window;
echo call :pu                   you *must* call this subroutine to show the drawing^^!
echo/
echo call :clearScreen          Clears the graphics window and resets all parameters
echo call :cs                   to their initial values, including Turtle position.
echo/
echo call :home                 Moves Turtle to center of window, pointing upwards.
echo/
echo call :setxy expr expr      Moves the Turtle to the given location (no drawing).
echo/
echo Two simple examples:
echo call :penDown ^& call :forward 100 ^& call :right 90 ^& call :fd 50 ^& call :penUp
echo call :pd ^& (for /L %%i in (1,1,12) do call :fd 190 ^& call :rt 150) ^& call :pu
echo/
echo Enter Batch Turtle Graphics commands; nothing to end:

:begin
rem Place here commands to execute before drawing graphics

rem Start Turtle Graphics
"%~F0" TurtleGraphics 3>&1 1>&2 | CScript //nologo //E:JScript "%~F0"
rem End Turtle Graphics

rem Place here commands to execute after drawing graphics
goto :EOF


:TurtleGraphics
rem Start of drawing commands
call :newwindow "Batch Turtle Graphics" 400 400

:nextCommand
   echo/
   echo Ready...
   set "command="
   set /P "command="
   if not defined command goto endCommands
   %command%
goto nextCommand
:endCommands

rem End of drawing commands
goto :EOF

============================================================

:newWindow title width height
:nw
set "_title=Batch Turtle Graphics"
set /A "_width=400, _height=400"
if "%~1" neq "" set "_title=%~1"
if "%~2" neq "" set /A "_width=%~2, _height=%~3"
echo openwindow;%_width%;%_height%;%_title% >&3
goto resetAll

:clearScreen
:cs
echo ctx.setTransform(1,0,0,1,0,0); ctx.clearRect(0,0,%_width%,%_height%); ctx.translate(%_width%/2,%_height%/2); >&3
echo ctx.strokeStyle="white"; ctx.lineWidth=1; document.body.style.background="black"; >&3
echo/>&3
:resetAll
set /A _pencolor=15, _pensize=1, _bgcolor=0
set "_fillcolor="
exit /B

:home
:ct = CenterTurtle
echo ctx.setTransform(1,0,0,1,0,0); ctx.translate(%_width%/2,%_height%/2); >&3
echo/>&3
exit /B

:setxy x y
:xy
echo ctx.moveTo(%~1,-(%~2)); ctx.translate(%~1,-(%~2)); >&3
exit /B

============================================================

:penDown
:pd
echo ctx.beginPath(); ctx.moveTo(0,0); >&3
exit /B

:penUp
:pu
if defined _fillcolor echo ctx.fill(); >&3
if defined _pencolor echo ctx.stroke(); >&3
echo/>&3
exit /B

:forward pixels
:fd
echo ctx.lineTo(0,-(%~1)); ctx.translate(0,-(%~1)); >&3
exit /B

:back pixels
:bk
echo ctx.lineTo(0,%~1); ctx.translate(0,%~1); >&3
exit /B

:right degrees
:rt
echo ctx.rotate((%~1)*Math.PI/180); >&3
exit /B

:left degrees
:lt
echo ctx.rotate(-(%~1)*Math.PI/180); >&3
exit /B

============================================================

:: End of Batch section


@end


// Start of JScript section

var fso      = new ActiveXObject("Scripting.FileSystemObject"),
    WshShell = new ActiveXObject("WScript.Shell"),
    HTA      = { Win: false }, command;

// Create the HTA file
HTA.FullName = WScript.ScriptFullName.replace(WScript.ScriptName,"BatchTurtleGraphics.hta");
HTA.File     = fso.CreateTextFile(HTA.FullName,true);
HTA.File.WriteLine(
   "<meta http-equiv='x-ua-compatible' content='ie=edge'/>\r\n" +
   "<html> <head><HTA:APPLICATION></head>\r\n" +
   "<script language='JavaScript'>\r\n" +
   "var fso   = new ActiveXObject('Scripting.FileSystemObject'),\r\n" +
   "    stdin = fso.GetStandardStream(0), command, canvas, ctx;\r\n" +
   "fso.GetStandardStream(1).WriteLine();  // send confirmation\r\n" +
   "eval(stdin.ReadLine());  // get initialization\r\n" +
   "function evalCommands() {while (command=stdin.ReadLine()) eval(command);}\r\n" +
   "window.onkeydown = evalCommands;\r\n" +
   "</script>\r\n" +
   "</html>\r\n"
);
HTA.File.Close();

// Receive commands from Batch section and send they to the HTA window
while ( ! WScript.Stdin.AtEndOfStream ) {

   command = WScript.Stdin.ReadLine();

   if ( command.substr(0,11) == "openwindow;" ) {

      // command = "openwindow;width;height;title" - create a new mshta.exe .HTA window

      // If is there a previous open window: leave it in the screen
      if ( HTA.Win ) {
         HTA.Win.Stdin.WriteLine("ignorekey=function () { }; window.onkeydown=ignorekey;\r\n");
         WshShell.AppActivate(HTA.Win.ProcessID);
         WshShell.SendKeys(" ");
      }

      // Open the HTA window and wait for confirmation
      HTA.Win = WshShell.Exec('mshta.exe "'+HTA.FullName+'"');
      HTA.Win.Stdout.ReadLine();

      // Initialize the contents of the HTA window
      var p = command.split(";"), width = p[1], height = p[2], title=p[3];
      command = "\"<title>"+title+"</title> " +
                  "<style type='text/css'>body {color:white; background:black;}</style> " +
                  "<canvas id='BTGcanvas' width='"+width+"' height='"+height+"' style='border:1px solid;'>" +
                     "Your browser don't support the HTML5 Canvas tag" +
                  "</canvas>\"";
      HTA.Win.Stdin.WriteLine(
         "window.resizeTo("+width+"+34,"+height+"+64); "   +   // try: 34..40 64..82
         "document.body.innerHTML = "+command+"; "         +
         "canvas = document.getElementById('BTGcanvas'); " +
         "ctx = canvas.getContext('2d'); "                 +
         "ctx.translate("+width+"/2,"+height+"/2);"        +
         "ctx.strokeStyle = 'white';"
      );

   } else {

      // Read and send commands to the (active) HTA window
      // until an "end of block" mark (empty line) is received
      while ( command ) {
         HTA.Win.Stdin.WriteLine(command);
         command = WScript.Stdin.ReadLine();
      }

      // Raise the event for "window.onkeydown" function in the HTA window
      HTA.Win.Stdin.WriteLine();         //    Send the "end of block" mark (empty line)
      WshShell.AppActivate(HTA.Win.ProcessID);      //    Set focus on the HTA window
      WshShell.SendKeys(" ");            //    And do a "key down"

   }

}

// Close the HTA window and delete the HTA file
HTA.Win.Stdin.WriteLine("window.close();\r\n");
WshShell.AppActivate(HTA.Win.ProcessID);
WshShell.SendKeys(" ");
fso.DeleteFile(HTA.FullName);

Previous Batch file allows an interactive execution of Batch code with BTG subroutines in a way rather similar to the one originally provided by Logo programming language, so this program may be taken as a learning tool to teach graphics (or to teach Batch file programming using graphics as base). You must note that this is a preliminary version of BTG so there are some aspects of Logo Turtle Graphics that are not yet implemented, like show the Turtle itself or manage line and fill colors. In the development of applications of this type we are limited by the usual restrictions of Batch files combined with the method used to emulate Logo behaviour under the scheme required by HTML5 canvas tag; this means that there are several details we must pay attention when using BTG subroutines:

  • You must call :penDown subroutine in order to start a drawing.
  • You must call :penUp subroutine to end the current drawing and show it on the screen. Nothing will appear in the graphics window until :penUp subroutine be called.
  • The number of graphics operations between call:penDown and call:penUp subroutines can not be very high. For example, in the last drawing example shown below, the most internal loop have 5 iterations and the next one have 19. If we move the call:pd/call:pu subroutines from the first loop to the second one, the number of iterations change from 5 to 19*5=95 and in this case, the program just freezes. Check this detail in first place if your drawings fails.
  • After the graphics are updated the graphics window keep the focus, so you must manually select the cmd.exe window in order to enter the next command.

Some of these restrictions will be solved in future BTG versions.

Below there are several one-line BTG drawings taken from interesting Logo Turtle Graphics examples that I converted to Batch. You may copy anyone of these lines and paste they in the cmd.exe BTG program input in order to produce the graphics; to do that, run the TurtleGraphics.bat program, select and copy the complete line of the desired example from the list below, right-click on the TurtleGraphics.bat cmd.exe window and select "Paste". Remember to first clear previous graphics with call :clear or open a new window with call :newWindow "Any title".

Code: Select all

The following examples were taken from: http://www.mathcats.com/gallery/15wordcontest.html
--------------------------------------------------------------------------------
Hypercube:
call :setxy -120 50 & for /L %i in (1,1,8) do call :pd & (for /L %j in (1,1,4) do call :rt 90 & call :fd 100) & call :bk 100 & call :lt 45 & call :pu
Compare how the graphics are displayed when the position of call:pd/call:pu subroutines is changed this way:
call :setxy -120 50 & call :pd & (for /L %i in (1,1,8) do (for /L %j in (1,1,4) do call :rt 90 & call :fd 100) & call :bk 100 & call :lt 45 ) & call :pu
In this case the 8*4=32 iterations are supported between call :pd and call :pu,
but this point also depends on the number and type of commands in the loops.
--------------------------------------------------------------------------------
Hexagon:
for %i in (100 50) do (for /L %j in (1,1,6) do call :pd & (for /L %k in (1,1,6) do call :fd %i & call :lt 60) & call :lt 60 & call :pu)
--------------------------------------------------------------------------------
Hexagon Variation:
for /L %i in (15,15,90) do call :pd & (for /L %j in (1,1,6) do (for /L %k in (1,1,6) do call :fd %i & call :rt 60) & call :rt 60) & call :pu
--------------------------------------------------------------------------------
Octa-star Spiral:
for /L %i in (0,4,104) do call :pd & (for /L %j in (1,1,8) do call :fd %i & call :rt 135) & call :fd %i & call :rt 30 & call :pu
--------------------------------------------------------------------------------
Penta-star Spiral:
for /L %i in (0,3,96) do call :pd & (for /L %j in (1,1,5) do call :fd %i & call :rt 144) & call :fd %i & call :rt 30 & call :pu
--------------------------------------------------------------------------------
Simple Flower:
for /L %j in (1,1,11) do ( for /L %i in (0,1,359) do call :pd & call :fd 1 & call :rt Math.sin(%i*Math.PI/360^) & call :pu )
--------------------------------------------------------------------------------
Five Rose:
for /L %i in (1,1,1800) do call :pd & call :fd 10 & call :rt %i+.1 & call :pu
The .1 can be replaced with other values to produce different figures, but the 1800 number must be adjusted accordingly;
for example, .2 generates a figure with 10 "roses" so it requires a value of 10*360=3600.
Other values are: 0.125=8 roses, 0.15=20 roses.
More details at: http://www.mathcats.com/gallery/fiverosedetails.html
--------------------------------------------------------------------------------
Dahlia: this drawing is amazing!
for /L %i in (1,1,8) do call :rt 45 & (for /L %j in (1,1,4) do call :rt 90 & (for /L %k in (1,1,90) do call :pd & call :fd 2 & call :rt 2 & call :pu ) )
The 4 can be replaced with 1 to 7 for other flowers.
--------------------------------------------------------------------------------
My own design:
call :rt 18 & for /L %i in (1,1,5) do call :rt 72 & (for /L %j in (190,-10,10) do call :pd & (for /L %k in (1,1,5) do call :fd %j & call :rt 144) & call :pu)

When there are several FOR commands nested in a long line, is convenient to change the position of the parentheses in order to clearly delimit the group of elements in each FOR (Logo style). For example, instead of "for /L %i in (1,1,N) do (call :first & call :second)" we may use "(for /L %i in (1,1,N) do call :first & call :second)".

This is the output that appeared in my screen after I executed four of the previous examples in a new graphics window each, and manually arranged the lay out:

Image

If you want to run a larger multi-line Batch Turtle Graphics program, just remove the part that appear between "rem Start of drawing commands" and "rem End of drawing commands" lines in previous Batch file and place your own code there. More examples coming soon...

Enjoy it! :D

Antonio

Meerkat
Posts: 83
Joined: 19 Jul 2015 02:27
Location: Philippines

Re: "Turtle Graphics" in Batch files!

#2 Post by Meerkat » 06 Sep 2015 23:07

It's simply amazing! :shock:

Now let me do some Batch art!!! :twisted:

Code: Select all

set "no=20" & for /l %i in (1,1,!no!) do (call :rt 360/!no! & for /L %k in (1,1,60) do call :pd & call :rt 6  & call :fd 7 & call :pu )

Image

You can change the value of !no! to change the number of circles to be displayed.

Meerkat

Post Reply