在LispWorks中进行编程23:龟图形

  • 0

在LispWorks中进行编程23:龟图形

Category:UI界面编写 Tags : 

龟图形

该项目演示了如何使用名为Turtle Graphics的系统在Lisp中创建简单图形,该系统最初由Seymour Papert作为数学教学工具开发。

Turtle Graphics基于控制一个叫做乌龟的小动物,它在计算机的屏幕上移动。它可以响应一些简单的命令,比如向前  移动乌龟向前移动一定数量的单位,  向右移动乌龟顺时针旋转指定的度数。向后向左的命令导致相反的运动。

乌龟在移动时会在屏幕上留下痕迹。你可以用下面的命令控制该抬笔落笔 ; 当笔下来时,乌龟画线。在原始系统中,乌龟在屏幕上显示为三角形光标; 在这个项目中,乌龟是看不见的。

举个例子,这是一系列绘制房屋的命令,以及最终的结果。乌龟从左下角开始:

(forward 100)(left 90)(forward 100)(left 30)(forward 100)(left 120)(forward 100)(left 30)(forward 100)

 

我们将实现龟图形作为Lisp程序,因此我们可以将它们包含在Lisp程序中以允许我们制作复杂的图。

完整列表

此内容查看价格为3雪花,请先

Lisp中的Turtle图形

第一步是创建一些全局变量来跟踪我们正在绘制的窗口,称为乌龟窗格,以及乌龟的位置和角度(以弧度表示):

(defparameter turtle-pane nil)(defparameter turtle-x 320)(defparameter turtle-y 240)(defparameter turtle-theta 0)(defparameter turtle-draw t)

窗口将是640 x 480像素,所以我们已经在窗口中间启动了乌龟。我们将提供一个重置命令来重置乌龟的位置和方向:

(defun reset ()  (setf turtle-x 320)  (setf turtle-y 240)  (setf turtle-theta 0)  (setf turtle-draw t))

LispWorks图形包提供了一个命令gpdraw-line来绘制一条线; 格式是:

(gp:draw-line pane from-x from-y to-x to-y)

这是前进的程序:

(defun forward (length)  (let ((new-x (+ turtle-x (* length (cos turtle-theta))))        (new-y (- turtle-y (* length (sin turtle-theta)))))    (if turtle-draw        (gp:draw-line turtle-pane turtle-x turtle-y new-x new-y))    (setf turtle-x new-x)    (setf turtle-y new-y)))

我们首先计算乌龟的新位置,new-xnew-y,从旧位置到新位置画一条线,最后更新turtle-xturtle-y。Lisp函数cossin以弧度给出它们的参数的余弦和正弦。

这是正确的程序。我们将角度转换为弧度,因为我们保持以弧度为单位的turtle-theta

(defun radians (angle)  (* pi (/ angle 180))) (defun right (angle)  (setf turtle-theta (- turtle-theta (radians angle))))

后退左边的定义非常简单:

(defun back (length)  (forward (- length))) (defun left (angle)  (right (- angle)))

最后抬笔落笔

(defun penup ()  (setf turtle-draw nil)) (defun pendown ()  (setf turtle-draw t))

在窗口中绘制图形

最后,我们需要命令来创建一个窗口,我们将在其上绘制乌龟图形。主例程plot创建一个名为capioutput-pane的区域,并调用capicontains以在纯窗口中显示它:

(defun plot ()  (capi:contain   (make-instance ‘capi:output-pane :display-callback ‘draw)   :best-width 640 :best-height 480))

创建窗口时,它会调用过程绘制来绘制图形。这是我们放置龟图形命令的地方。例如,这是绘制房屋的示例:

(defun draw (pane &optional x y width height)  (declare (ignore x y width height))  (setf turtle-pane pane)  (reset)  (forward 100)  (left 90)  (forward 100)  (left 30)  (forward 100)  (left 120)  (forward 100)  (left 30)  (forward 100))

抽奖过程会被这里不需要额外的参数; 该声明 忽略线停止这些生成错误消息时编译的过程。

最后,通过调用以下命令运行乌龟:

(plot)

现在让我们看一些更有趣的图形示例。

向内螺旋

向内螺旋是曲率增加的曲线。我们可以定义如下:

(defun inspi (side angle inc count)  (forward side)  (right angle)  (if (> count 0)      (inspi side (+ angle inc) inc (- count 1))))

这里是螺旋形的各段的长度,角度为起始角,INC是增量的角度,和计数是我们重复命令的次数(否则它会永远持续下去)。

这是为angle = 20和inc = 2 绘制的调用:

(defun draw (pane &optional x y width height)  (declare (ignore x y width height))  (setf turtle-pane pane)  (reset)  (inspi 50 2 20 1000))

结果:

以下是angleinc其他一些值:

  • angle=0, inc=7
  • angle=40, inc=30

这是一个有趣的数学问题,可以解决为什么例程给出它在这些情况下的形状。

龙曲线

这是第二个例子; 它是一条称为龙曲线的递归曲线。

它由两个例程定义; 一个左撇子版本ldragon和一个右撇子版本rdragon

(defun ldragon (size level)  (if (= level 0)      (forward size)    (progn      (ldragon size (- level 1))      (left 90)      (rdragon size (- level 1))))) (defun rdragon (size level)  (if (= level 0)      (forward size)    (progn      (ldragon size (- level 1))      (right 90)      (rdragon size (- level 1)))))

这是绘制 11级曲线的绘图程序:

(defun draw (pane &optional x y width height)  (declare (ignore x y width height))  (setf turtle-pane pane)  (reset)  (ldragon 4 11))

最后,结果如下:

参考

有关龟图形的详细描述,可以直接在Lisp中实现的许多其他示例,以及它们背后的数学,请参阅Harold Abelson和Andrea DiSessa,MIT出版社,1980年出版的“Turtle Geometry”一书,该书仍在印刷中。

http://mip.i3geek.com

Leave a Reply

搜索

分类目录

公 告

本网站学习论坛:

www.zhlisp.com

lisp中文学习源码:

https://github.com/zhlisp/

欢迎大家来到本站,请积极评论发言;

加QQ群学习交流。