#! /usr/bin/gawk -f # # spirolang.awk - Translates a description of a spirographic-like plot # into the appropriate gnuplot orders. This awk script understands and # translates a collection of instructions, forming a minilanguage for a # subset of spirographic-like drawings. # # PROGRAM USE: spirolang.awk # where is a file containing the description of the # spirographic curves. The suffix ".spr" is customary for the input file. # #----------------------------------------------------------------------- # # CopyRight (c): Victor Lua~na, Sept. 22, 2006 # Departamento de Quimica Fisica y Analitica # Universidad de Oviedo, 33007-Oviedo, Spain # victor@carbono.quimica.uniovi.es # # This script is distributed as an Open Source code protected by the # GNU General Public License version 2 (GPL2) as published by the # Free Software Foundation (http://www.gnu.org). # In short: you can make and distribute copies of this script; you can # also make changes in the code and distribute the modified files; but # you should always document the introduced changes and you must distribute # or make available to others the source codes. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #----------------------------------------------------------------------- # # Language description: # + Orders are written in capitals: LIKE THIS. # + Obligatory variables are written withing and have # a suffix according to the expected type of data: # ..... string data: like_this. # ..... an integer: -413. # ..... a real value: -27.2e-4. # .... a real expression (containing no blanks): # 2*pi/14. # ..... a complex value: {-1.4,0.85}. # .... a complex expression: pi*{0,1}. # + Optional data are written withing [square brackets]. # #----------------------------------------------------------------------- # # Orders recognized by this script: # # * PROJECT # The project name serves as root for the names of all the files, # temporary or final, that the drawing process requires. # Default: projectname = "tmp" # # * TERMINAL [parameters.s] # Select a gnuplot terminal type. Typical elections would be PNG or # EPS, but any type accepted by gnuplot will serve. This order will # be translated into the next gnuplot instruction: # set terminal [parameter.s] # Default: png size 600,600 x000000 xffffff x404040 ... # # * CURVE [samples.i] # Start a new curve. A plot is formed by one or more curves. Each # curve is made by one or more terms. Each curve is computed # independently and written to a temporary file. All curves are # plotted together at the end to form the final image. # The default number of sample points (2001) can be changed # independently for each curve. Some special term types (like # TROCHOID) may take control of this and ignore the # value. # # The general form of a curve is: # # z(t) = z1(t) + z2(t) + ... # # where t is the independent parameter, zk(t) = xk(t) + i yk(t) is a # complex term contribution to the curve. # # * STYLE # Take control of the gnuplot style for this curve. The # must follow gnuplot syntax. For instance: # + use same color on all lines ---> style lt 1 # + use points instead of lines ---> style with points pt -1 # Default: style = "" # (The default style is to use lines for the curves, increasing # the line style for each successive curve, including those implied # by the loops) # # * LOOP [var_inc.r] # Repeat the current curve according to the next implicit loop: # var = var_ini # while (var does not reach var_end) do # compute and draw a new installment of the current curve # var = var_ini + (var_inc) # end # The string can be used in the definition of the curve # terms (see the examples below). # The value can be negative. # The curve must be repeated less that 1000 times. # Defaults: no loop, var_inc = 1 # # * ADDTERM LINE # A linear term contribution to the current curve: # zk(t) = z0 + (z1-z0) * t # The line passes through z0 and z1, two arbitrary points in the # complex plane. Remember than complex values are entered using the # gnuplot notation: {x,y} means "x+i*y". Blank character must be # avoid within each number. # # * ADDTERM SPIRAL1 [n.i] # Generalized Archimedes spiral: # zk(t) = a * (2*pi*t)**n * exp(i*2*pi*t) # Default: n = 1. # # * ADDTERM SPIRAL2 # Equiangular spiral: # zk(t) = a * exp(t/tan(b)) * exp(i*2*pi*t) # Maximize the number of spiral rolls by choosing b close to plus # or minus pi/2 (approx. 1.570796). # # * ADDTERM TROCHOID [samples.i] # A trochoid term: # zk(t) = (R-r)*exp(i*2*pi*t) + p*exp(-i*2*pi*(R-r)*t/r) # If samples is given, the number of sampling points and the number # of curve rollings is internally computed. # # * ADDTERM WHEEL # A Farris rolling wheel term: # zk(t) = a * exp(i*2*pi*(n*t+s)) # The meaning of the parameters is: # + a .......... wheel radius. # + n .......... rolling frequency, i.e. number of rolls of the # wheel when t goes from 0 to 1. # + s .......... initial phase angle. # # * TRANGE # Range for the t variable. Notice that the presence of a trochoid # term may take control for t and ignore this input. # Default: t0 = 0, t1 = 1. # # * GFACTORS # Multiplicative factors for the real and imaginary parts of the # drawn functions. In other words, the image finally drawn is: # plot freal*real(z(t)), fimag*imag(z(t)) # Default: freal = fimag = 1.0 # # * LABEL # Add a gnuplot label at the indicated position. The plot center # has coordinates (0,0). The label is centered on the (x,y) point. # The plot can contain any number of labels, but the program makes # no attempt to avoid the collision between labels. # Default: no labels. # #----------------------------------------------------------------------- # # Example 1: # # project plot01 # curve 10 # addterm trochoid 100 -49 76 # #----------------------------------------------------------------------- # # Example 2: # # project plot02 # terminal png size 600,600 x000000 # curve # loop kkk 0 20 1 # addterm wheel 4*0.98**kkk -3 kkk/200. # addterm wheel 5*1.02**kkk 2 kkk/200. # #----------------------------------------------------------------------- # # Example 3: # # project plot03 # terminal png size 600,600 x000000 # curve # style lt 1 # loop kkk 0 20 1 # addterm wheel 4 -5 -kkk/60. # addterm wheel 3 2 kkk/60. # addterm wheel 2 9 0. # #----------------------------------------------------------------------- # # Example 4: # # project plot04 # terminal postscript eps enhanced color "Helvetica" 48 # gfactors 1.4 0.7 # curve # # All lines with the same color and type # style lt 1 # # Several copies of the curve, each smaller than the previous one. # loop kkk 0 10 1 # addterm wheel 200*0.96**kkk 1 0. # addterm wheel 10*0.96**kkk 9 0. # addterm wheel 9*0.96**kkk 23 0. # # Add a message in the central hole. # label 0 0 G_nuplot rules! # #----------------------------------------------------------------------- function sign (x) { return ( x >= 0.0 ? +1.0 : -1.0 ) } BEGIN { ######################################################################## ###--------CHECK THE NAMES OF THE NEXT PROGRAMS ON YOUR SYSTEM-------### ###----------You may want to add viewers for other terminals---------### ######################################################################## program_gnuplot = "gnuplot4" program_png_viewer = "xv" program_eps_viewer = "gv" program_pdf_viewer = "gv" program_fixbb = "fixbb" program_epstopdf = "epstopdf" ######################################################################## ###--------CHECK THE "set terminal pgn" SINTAX ON YOUR GNUPLOT-------### ######################################################################## term_type = "png" #term_param = "png size 600,600 x000000 xffffff x404040 xff0000 xffa500 x66cdaa xcdb5cd xadd8e6 x0000ff xdda0dd x9500d3" term_param = "png picsize 600 600 x000000 xffffff x404040 xff0000 xffa500 x66cdaa xcdb5cd xadd8e6 x0000ff xdda0dd x9500d3" term_suffix = ".png" ######################################################################## projectname = "tmp" def_samples = 2001 trange0 = 0.0 trange1 = 1.0 freal = 1.0 fimag = 1.0 ncurve = 0 nlabel = 0 # type_line = 101 type_wheel = 102 type_trochoid = 103 type_spiral1 = 104 type_spiral2 = 105 } /^#/ { next } # Skip commentaries toupper($1) == "PROJECT" { projectname = $2 next } toupper($1) == "TERMINAL" { #for (k=1; k<=2; k++) { $(k) = "" } $1 = "" sub("^ *", "", $0) term_param = $0 if (toupper(term_param) ~ /PNG/) { term_type = "png" term_suffix = ".png" } else if (toupper(term_param) ~ /EPS/) { term_type = "eps" term_suffix = ".eps" } else if (toupper(term_param) ~ /PDF/) { term_type = "pdf" term_suffix = ".pdf" } else { print "Warning: Unknown terminal type -> ", $0 term_type = "unk" term_suffix = ".unk" } next } toupper($1) == "CURVE" { ncurve++ curve_nterm[ncurve] = 0 curve_samp[ncurve] = def_samples if ($2+0 > 0) { curve_samp[ncurve] = $2 } curve_loop[ncurve] = 0 curve_loop_var[ncurve] = "none" curve_loop_vini[ncurve] = 0.0 curve_loop_vfin[ncurve] = 0.0 curve_loop_vinc[ncurve] = 1.0 curve_loop_nl[ncurve] = 1 curve_style[ncurve] = "" next } toupper($1) == "LOOP" { curve_loop[ncurve] = 1 curve_loop_var[ncurve] = $2 curve_loop_vini[ncurve] = $3+0 curve_loop_vfin[ncurve] = $4+0 curve_loop_vinc[ncurve] = 1.0 if ($5+0 > 0) { curve_loop_vinc[ncurve] = $5+0 } nloop = 0 vact = curve_loop_vini[ncurve] sig = sign(curve_loop_vinc[ncurve]) l = 0 while (sig*vact <= sig*curve_loop_vfin[ncurve]) { l++ vact += curve_loop_vinc[ncurve] if (l>=1000) { print "ERROR: Curve loops should not exceed the count of 1000" print "The error happened on curve ", ncurve print "Offending line -> ", $0 exit (-1) } } curve_loop_nl[ncurve] = l next } toupper($1) == "STYLE" { $1 = "" curve_style[ncurve] = $0 next } toupper($1) == "ADDTERM" && toupper($2) == "LINE" { k = ++curve_nterm[ncurve] curve_termtype[ncurve,k] = type_line curve_termparam[ncurve,k,1] = $3 # z0 curve_termparam[ncurve,k,2] = $4 # z1 next } toupper($1) == "ADDTERM" && toupper($2) == "SPIRAL1" { k = ++curve_nterm[ncurve] curve_termtype[ncurve,k] = type_spiral1 curve_termparam[ncurve,k,1] = $3 # a if ($4+0 > 0) { curve_termparam[ncurve,k,2] = $4 } # n else { curve_termparam[ncurve,k,2] = 1 } # n next } toupper($1) == "ADDTERM" && toupper($2) == "SPIRAL2" { k = ++curve_nterm[ncurve] curve_termtype[ncurve,k] = type_spiral1 curve_termparam[ncurve,k,1] = $3 # a curve_termparam[ncurve,k,2] = $4 # b next } toupper($1) == "ADDTERM" && toupper($2) == "WHEEL" { k = ++curve_nterm[ncurve] curve_termtype[ncurve,k] = type_wheel curve_termparam[ncurve,k,1] = $3 # a curve_termparam[ncurve,k,2] = $4 # n curve_termparam[ncurve,k,3] = $5 # s next } toupper($1) == "ADDTERM" && toupper($2) == "TROCHOID" { k = ++curve_nterm[ncurve] curve_termtype[ncurve,k] = type_trochoid curve_termparam[ncurve,k,1] = $3 # R curve_termparam[ncurve,k,2] = $4 # r curve_termparam[ncurve,k,3] = $5 # p if ($6+0 > 0) { curve_termparam[ncurve,k,4] = $6 } # sampling else { curve_termparam[ncurve,k,4] = curve_samp[ncurve] } next } toupper($1) == "ADDTERM" { print "Warning: Unknown term type --> ", $0 next } toupper($1) == "TRANGE" { trange0 = $2+0 trange1 = $3+0 next } toupper($1) == "GFACTORS" { freal = $2+0 fimag = $3+0 next } toupper($1) == "LABEL" { nlabel++ lab_x[nlabel] = $2 lab_y[nlabel] = $3 $1 = ""; $2 = ""; $3 = "" sub("^ *", "", $0) lab_text[nlabel] = $0 next } END { #DEBUG-START #print "Curves: ", ncurve #for (j=1; j<=ncurve; j++) { # print "Curve:", j, " Loop:", curve_loop_nl[j], " Terms:", curve_nterm[j] # } #DEBUG_END outfile = projectname term_suffix gnufile = projectname ".gnu" # # HEADINGS: plot conditions and auxiliary functions: # print "set size ratio -1" > gnufile print "set nokey" >> gnufile print "set noxtics" >> gnufile print "set noytics" >> gnufile print "set noborder" >> gnufile print "set parametric" >> gnufile print "i2p = {0,1}*2*pi" >> gnufile print "gcd(x,y) = (x%y==0 ? y : gcd(y,x%y))" >> gnufile print "min(x,y) = (x> gnufile print "max(x,y) = (x>y ? x : y)" >> gnufile # # A function name and a data file is created for each curve to be plot: # for (j=1; j<=ncurve; j++) { for (l=1; l<=curve_loop_nl[j]; l++) { istrochoid = 0 vact = curve_loop_vini[j] + (l-1) * curve_loop_vinc[j] printf "%s = %f\n", curve_loop_var[j], vact >> gnufile curve_name[j,l] = sprintf ("z%03d%03d", j, l) curve_file[j,l] = sprintf ("%s%03d%03d%s", projectname, j, l, ".dat") printf "%s(t) = ", curve_name[j,l] >> gnufile for (k=1; k<=curve_nterm[j]; k++) { if (curve_termtype[j,k] == type_line) { printf "+ %s + (%s-%s)*t ", curve_termparam[j,k,1] \ , curve_termparam[j,k,2], curve_termparam[j,k,1] \ >> gnufile } else if (curve_termtype[j,k] == type_spiral1) { printf "+ %s * (2*pi*t)**%s * exp(i2p*t) "\ , curve_termparam[j,k,1], curve_termparam[j,k,2] \ >> gnufile } else if (curve_termtype[j,k] == type_spiral2) { printf "+ %s * exp(t/tan(%s)) * exp(i2p*t) "\ , curve_termparam[j,k,1], curve_termparam[j,k,2] \ >> gnufile } else if (curve_termtype[j,k] == type_wheel) { printf "+ %s * exp(i2p*(%s*t+%s)) "\ , curve_termparam[j,k,1], curve_termparam[j,k,2] \ , curve_termparam[j,k,3] \ >> gnufile } else if (curve_termtype[j,k] == type_trochoid) { istrochoid = 1 resolution = curve_termparam[j,k,4] Rbig = curve_termparam[j,k,1] rsmall = curve_termparam[j,k,2] printf "+ (%s-%s)*exp(i2p*t) + %s*exp(-i2p*(%s-%s)*t/%s) "\ , curve_termparam[j,k,1], curve_termparam[j,k,2] \ , curve_termparam[j,k,3], curve_termparam[j,k,1] \ , curve_termparam[j,k,2], curve_termparam[j,k,2] \ >> gnufile } } printf "\n" >> gnufile printf "set terminal table\n" >> gnufile printf "set output \"%s\"\n", curve_file[j,l] >> gnufile if (istrochoid == 1) { printf "res = %s\n", resolution >> gnufile printf "rr = int(abs(%s))\n", rsmall >> gnufile printf "nturns = rr/gcd(int(%s),rr)\n", Rbig >> gnufile printf "set samples (1+res*nturns)\n" >> gnufile printf "t0 = %s\n", trange0 >> gnufile printf "t1 = nturns*%s\n", trange1 >> gnufile } else { printf "set samples %d\n", curve_samp[j] >> gnufile printf "t0 = %s\n", trange0 >> gnufile printf "t1 = %s\n", trange1 >> gnufile } printf "plot [t=t0:t1] %s*real(%s(t)),%s*imag(%s(t))\n" \ , freal, curve_name[j,l], fimag, curve_name[j,l] >> gnufile } } printf "set terminal %s\n", term_param >> gnufile printf "set output \"%s\"\n", outfile >> gnufile printf "set data style lines\n" >> gnufile printf "set noparametric\n" >> gnufile for (i = 1; i <= nlabel; i++) { printf "set label \"%s\" at %s,%s center\n" \ , lab_text[i], lab_x[i], lab_y[i] >> gnufile } printf "plot" >> gnufile comma = "" for (j=1; j<=ncurve; j++) { for (l=1; l<=curve_loop_nl[j]; l++) { printf "%s \"%s\" %s", comma, curve_file[j,l], curve_style[j] \ >> gnufile comma = "," } } printf "\n" >> gnufile # # FINAL STEP: run gnuplot and view the result. # order = sprintf ("%s %s", program_gnuplot, gnufile) system (order) if (tolower(term_type) == "png") { order = sprintf ("%s %s", program_png_viewer, outfile) } else if (tolower(term_type) == "eps") { order = sprintf ("%s %s", program_eps_viewer, outfile) } else { order = sprintf ("echo 'Final plot of unknown type ->' %s", outfile) } system (order) }