;;; This is my first time using gnuplot, so there are probably some ways to improve this. ;;; Dana Nau, April 3, 2010 ;;; Updated April 4, 2010. Fixed two ridiculously stupid errors: the above creation date was off ;;; by a year, and the gnuplot commands created a file with a .gif suffix whose contents were ;;; postscript rather than gif. While I was at it, I made it easy to create something ;;; other than gif output: just set the global variable OUTPUT-TYPE to whatever you want. ;;; Change OUTPUT-TYPE if you want gnuplot to create something other than a gif file, (defvar output-type "gif") ;;; Change GNUPLOT-SUFFIX if you prefer a different suffix for the gnuplot file. (defvar gnuplot-suffix "gnuplot") ;;; PLOT-RACETRACK generates gnuplot code to draw a racetrack as an image file. ;;; The first argument, NAME, is a filename (without suffix); PLOT-RACETRACK will create ;;; a "NAME.gnuplot" file consisting of gnuplot commands to create a "NAME.gif" file. ;;; The 2nd argument, BOUNDARY, is the racetrack's boundary as in the project description. ;;; START, FINISH, and PATH are optional arguments: START is the racecar's initial state, ;;; FINISH is the finish line, and PATH is your path for the racecar (if you have one). (defun plot-racetrack (name boundary &optional start finish path) (with-open-file (ostream (concatenate 'string name "." gnuplot-suffix) :direction :output :if-exists :rename) (format ostream "# gnuplot commands to plot racetrack ~s" name) (format ostream "~%set xtics 1; set ytics 1; set grid") ;; Improve the aspect ratio. It still isn't 1-to-1, but I don't know how to get that (format ostream "~%set size square") (format ostream "~%set terminal ~a; set output '~a.~a'" output-type name output-type) ;; if there's a finish line, generate gnuplot code for it (cond (finish (format ostream "~%# draw the finish line as a double-headed arrow") (let ((p1 (first finish)) (p2 (second finish))) (format ostream "~%set arrow 1 from ~a,~a to ~a,~a" (first p1) (second p1) (first p2) (second p2)) (format ostream "~%set arrow 2 from ~a,~a to ~a,~a" (first p2) (second p2) (first p1) (second p1))))) ;; generate the plot command to draw the boundary from inline data (format ostream "~%plot '-' with lines lt 1") ;; if there's a starting point or path, add them to the plot command (if finish (format ostream ", '-' pt 4")) (if path (format ostream ", '-' with linespoints 2")) ;; write inline data for the boundary (format ostream "~%# draw the boundary") (dolist (edge boundary) (let ((p1 (first edge)) (p2 (second edge))) (format ostream "~%~s ~s~%~s ~s~%" (first p1) (second p1) (first p2) (second p2)))) (format ostream "e~%") ; tell gnuplot the inline data is finished ;; write inline data for the starting-point data, if there is one (cond (start (format ostream "~%# plot the racecar's starting point") (let* ((p1 (first start)) (x (first p1)) (y (second p1))) (if (not (and (integerp x) (integerp y))) (format t "~%Warning: starting point ~s doesn't consist of integers" state)) (format ostream "~%~s ~s~%" x y)) (format ostream "e~%"))) ; tell gnuplot the inline data is finished ;; write inline data for the racecar path, if there is one (cond (path (format ostream "~%# draw the racecar's path") (dolist (state path) (let* ((loc (first state)) (x (first loc)) (y (second loc)) (velocity (second state)) (v (first velocity)) (w (second velocity))) (if (not (and (integerp x) (integerp y) (integerp v) (integerp w))) (format t "~%Warning: state ~s doesn't consist of integers" state)) ;; the racecar went to (x,y) at velocity (u,v), so it came from (x-u, y-v) (format ostream "~%~s ~s~%~s ~s~%" (- x v) (- y w) x y))) (format ostream "e~%"))) ; tell gnuplot the inline data is finished (format t "~%Wrote the gnuplot commands to this file: ~a.~a" name gnuplot-suffix) (format t "~%Gnuplot's output will go into this file: ~a.~a" name output-type))) ;;; ------------------------------------------------------------------------ ;;; What follows is a demo of how to use the PLOT-RACETRACK function. ;;; Modify it if you want to make a gnuplot file of your own racetrack. ;;; ------------------------------------------------------------------------ (setq boundary '(((4.1 0) (14 0)) ((18 14) (14 18)) ((0 14) (0 4)) ((0 10) (4 10)) ((11 5) (11 10)) ((14 14)(4.1 14)) ((14 0) (18 3.9)) ((18 3.9) (18 14)) ((14 18)(4.2 18)) ((4.2 18) (0 14)) ((0 4) (4.1 0)) ((4 10) (4 5)) ((4 5) (14 5)) ((11 10) (9 11)) ((14 5) (14 14)) ((4.1 14) (8 7)))) (setq start '((1 8) (0 0))) (setq finish '((11 9) (14 9))) (setq path '(((1 8) (0 0)) ((2 7) (1 -1)) ((3 5) (1 -2)) ((5 3) (2 -2)) ((8 2) (3 -1)) ((11 2) (3 0)) ((14 3) (3 1)) ((16 5) (2 2)) ((17 8) (1 3)) ((17 11) (0 3)) ((16 14) (-1 3)) ((14 16) (-2 2)) ((11 17) (-3 1)) ((8 17) (-3 0)) ((5 16) (-3 -1)) ((3 15) (-2 -1)) ((2 14) (-1 -1)) ((2 13) (0 -1)) ((3 12) (1 -1)) ((5 10) (2 -2)) ((6 8) (1 -2)) ((7 7) (1 -1)) ((8 6) (1 -1)) ((9 6) (1 0)) ((9 7) (0 1)) ((8 9) (-1 2)) ((8 11) (0 2)) ((9 12) (1 1)) ((11 12) (2 0)) ((12 11) (1 -1)) ((12 9) (0 -2)))) (plot-racetrack "demo-plot" boundary start finish path)