diff --git a/墨干编辑器/TeXmacs图形编程.tm b/墨干编辑器/TeXmacs图形编程.tm new file mode 100644 index 0000000..68e8a40 --- /dev/null +++ b/墨干编辑器/TeXmacs图形编程.tm @@ -0,0 +1,800 @@ + + +> + +<\body> + \; + + 图形编程>||>>|>> + + + + 因为的介绍资料不多,所以打算边学边写,写一系列用作图的小文章。早先我在自己的博客上写过两篇:使用Scheme在中生成图片<\footnote> + + 和使用Scheme在中画内核代码结构体关系图<\footnote> + + ,对其图形系统的文档树有一个大概的了解。这次打算系统性地介绍作图方法并构建用编程作图的配置文件。 + + 本文对读者的基本要求就是熟悉的基本使用和语言的基础。相关的操作和内部原理,我尽量会使用自己的语言阐述清楚,或者给出官方文档的具体位置。另外,本文原始文档托管在Github<\footnote> + + 上,所使用的版本为。 + + + <\remark> + 由于文中使用了大量交互式进程,在原始文档中才能够对其求值并作图,所以请使用阅读原始文档。 + + > + + 本文的交互式代码的执行假定读者是一次性从上到下读完全文,当然这是不现实的,所以附录的小贴士建议优先阅读,以方便你第二次阅读本文中末节时快速进入状态。 + + + + 首先,假设我们已经了解到:一篇文档实际上就是一长串代码,通过渲染引擎的加工,这些代码得以展现在我们笔记本的屏幕上。这些代码我们称之为 + 。为了区分,我们将在中运行的代码称为 + 。 + + 通过,我们得到一个 + 。我们定义第一个函数 + + <\session|scheme|default> + <\input|Scheme] > + (define (plot l) (stree-\tree l)) + ;按下回车,定义这个函数 + + + + 一串代码对应的结构是一棵树,这里的tree>就是将 + 树转变成 树,以便在文档中显示。比如,我们知道的内部表示实际上就是。于是,在中,我们就可以通过 + + <\session|scheme|default> + <\folded-io|Scheme] > + (plot `(frac 1 2)) ;光标放在这行上,按下回车就能得到1/2 + <|folded-io> + \; + + + + + + 上面介绍的原语实际上用于数学模式,下面我们介绍图形模式下的原语。先全部列出来: + + <\big-table|>>>>| + 原语 + |<\cell> + 示例 + |<\cell> + 功能 + >| + + |<\cell> + > + |<\cell> + 坐标(0,0)处的一个点 + >| + + |<\cell> + + (line (point \P0\Q \P0\Q) (point \P0\Q \P1\Q) + + (point \P1\Q \P1\Q)) + > + |<\cell> + (0,0)>(0,1)>(1,1) + + 的一条折线 + >| + + |<\cell> + <\code*> + (cline (point \P0\Q \P0\Q) (point \P0\Q \P1\Q) + + (point \P1\Q \P1\Q)) + + |<\cell> + (0,1)\(1,1)\(0,0)> + + 的一条闭合折线 + >| + + |<\cell> + <\code*> + (spline (point \P0\Q \P0\Q) (point \P0\Q \P1\Q) + + (point \P1\Q \P1\Q)) + + |<\cell> + (0,1)\(1,1)> + + 的一条样条曲线 + >| + + |<\cell> + <\code*> + (cspline (point \P0\Q \P0\Q) (point \P0\Q \P1\Q) + + (point \P1\Q \P1\Q)) + + |<\cell> + (0,1)\(1,1)\(0,0)> + + 的一条闭合样条曲线 + >| + + |<\cell> + <\code*> + (arc (point \P0\Q \P0\Q) (point \P0\Q \P1\Q) + + (point \P1\Q \P1\Q)) + + |<\cell> + 过这三点的一条弧 + >| + + |<\cell> + <\code*> + (carc (point \P0\Q \P0\Q) (point \P0\Q \P1\Q) + + (point \P1\Q \P1\Q)) + + |<\cell> + 过这三点的一个圆 + >| + + |<\cell> + <\code*> + (text-at (texmacs-markup) + + (point \P0\Q \P0\Q)) + + |<\cell> + 这个原语的重要之处在于提 + + 供了一种在图片上放置 + + 图片的方法,放在其上 + + 的图片所处的位置是点 + + (0,0)的右边,其竖直方向 + + 上的对称轴正好过点(0,0) + >>>>> + \; + + + 接着,我们在这些原语<\footnote> + 这些原语的代码实现可以在下找到 + 的基础上构建作图所需的基本元素。首先是点,线段,矩形和圆: + + <\session|scheme|default> + <\input|Scheme] > + (define (point x y) + + \ \ ; number-\string的作用是将树变成文档中表示数据的字符串 + + \ \ `(point ,(number-\string x) ,(number-\string y))) + + + <\input|Scheme] > + (define (point.x point) + + \ \ (string-\number (list-ref point 1))) + + + <\input|Scheme] > + (define (point.y point) + + \ \ (string-\number (list-ref point 2))) + + + <\input|Scheme] > + (define (line . points) + + \ \ (cond ((nlist? points) `()) + + \ \ \ \ \ \ \ \ ((== points '()) `()) + + \ \ \ \ \ \ \ \ (else `(line ,@points)))) + + + <\input|Scheme] > + (define (rectangle leftdown rightup) + + \ \ (let ((leftup (point (point.x leftdown) (point.y rightup))) + + \ \ \ \ \ \ \ \ (rightdown (point (point.x rightup) (point.y + leftdown)))) + + \ \ \ \ `(cline ,leftdown ,leftup ,rightup ,rightdown))) + + + <\input|Scheme] > + (define (circle center radius) + + \ \ (let ((p1 (point (- (point.x center) radius) (point.y center))) + + \ \ \ \ \ \ \ \ (p2 (point (point.x center) (+ (point.y center) + radius))) + + \ \ \ \ \ \ \ \ (p3 (point (+ (point.x center) radius) (point.y + center)))) + + \ \ \ \ `(carc ,p1 ,p2 ,p3))) + + + + 用绘制点、矩形和圆: + + <\session|scheme|default> + <\unfolded-io|Scheme] > + (plot (point 0 0)) + <|unfolded-io> + > + + + <\unfolded-io|Scheme] > + (plot (rectangle (point 0 0) (point 1 1))) + <|unfolded-io> + |||>> + + + <\unfolded-io|Scheme] > + (plot (circle (point 0 0) 1)) + <|unfolded-io> + ||>> + + + + + + 使用原语可以给对象附上各种属性。比如 + + <\session|scheme|default> + <\unfolded-io|Scheme] > + (plot `(with color "red" fill-color "#eeeeee" ,(circle (point 0 0) 1))) + <|unfolded-io> + ||>>> + + + <\unfolded-io|Scheme] > + (plot `(with arrow-begin "\gtr\" dash-style "11100" + ,(line (point 0 1) (point 0 0) (point 1 1)))) + <|unfolded-io> + |dash-style|11100|||>>> + + + <\unfolded-io|Scheme] > + (plot `(with point-style "star" ,(point 0 0))) + <|unfolded-io> + >> + + + + 根据源码<\footnote> + + 中的定义,可以总结出: + + |||||| + 属性 + |<\cell> + 值 + |<\cell> + 作用 + >| + color + |<\cell> + \; + + 颜色,如 + |<\cell> + 对象本身的颜色 + >| + fill-color + |<\cell> + \; + |<\cell> + 填充色 + >| + magnify + |<\cell> + 浮点数,如 + |<\cell> + 放大或缩小的倍率 + >| + opacity + |<\cell> + 百分比,如 + |<\cell> + 透明度 + >| + point-style + |<\cell> + + |<\cell> + 点的样式 + >| + dash-style + |<\cell> + + |<\cell> + 线的样式 + >| + arrow-begin + |<\cell> + less\","\less\\|","\less\\less\",> + + gtr\","\|\gtr\","\gtr\\gtr\"> + + \; + |<\cell> + 开始处的箭头 + >| + arrow-end + |<\cell> + \; + |<\cell> + 结束处的箭头 + >>>>|部分对象属性> + + 光看表格中的总结不免失之直观,推荐阅读这章中样式属性详述这一节。 + + 下面,定义一些函数,方便我们操纵上一节中点、圆和矩形的样式。首先是颜色,我们定义来设置背景色,定义来设置前景色。粗糙的想法是在图形对象前增加标签以及相应的属性,标签会怎样呢?> + 这个问题可以用函数解决,另外我们定义来设置任意属性: + + <\session|scheme|default> + <\input|Scheme] > + (define (merge-with l par val subs) + + \ \ (cond ((== (length l) 0) '()) + + \ \ \ \ \ \ \ \ ((== (length l) 1) (append (list par val) l)) + + \ \ \ \ \ \ \ \ ((== par (car l)) + + \ \ \ \ \ \ \ \ \ (if subs (set-car! (cdr l) val)) l) + + \ \ \ \ \ \ \ \ (else\ + + \ \ \ \ \ \ \ \ \ \ (let ((t (list (car l) (cadr l)))) + + \ \ \ \ \ \ \ \ \ \ \ \ (append t (merge-with (cddr l) par val + subs)))))) + + + <\input|Scheme] > + (define (decorate l par val subs) + + \ \ (cond ((or (nlist? l) (null? l)) '()) + + \ \ \ \ \ \ \ \ ((list? (car l))\ + + \ \ \ \ \ \ \ \ \ (append (list (decorate (car l) par val subs))\ + + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (decorate (cdr l) par val subs))) + + \ \ \ \ \ \ \ \ ((== (car l) 'with)\ + + \ \ \ \ \ \ \ \ \ (append '(with) (merge-with (cdr l) par val subs))) + + \ \ \ \ \ \ \ \ ((or (== (car l) 'line) (== (car l) 'cline) (== (car l) + 'carc) (== (car l) 'point) (== (car l) 'graphics)) + + \ \ \ \ \ \ \ \ \ (append '(with) (merge-with (list l) par val + subs))))) + + + <\input|Scheme] > + (define (fill fig bc) + + \ \ (decorate fig "fill-color" bc #f)) + + + <\input|Scheme] > + (define (force-fill fig bc) + + \ \ (decorate fig "fill-color" bc #t)) + + + <\input|Scheme] > + (define (colorize fig fc) + + \ \ (decorate fig "color" fc #f)) + + + <\input|Scheme] > + (define (force-colorize fig fc) + + \ \ (decorate fig "color" fc #t)) + + + <\input|Scheme] > + (define (arrow-begin fig style) + + \ \ (decorate fig "arrow-begin" style #f)) + + + <\input|Scheme] > + (define (force-arrow-begin fig style) + + \ \ (decorate fig "arrow-begin" style #t)) + + + <\input|Scheme] > + (define (arrow-end fig style) + + \ \ (decorate fig "arrow-end" style #f)) + + + <\input|Scheme] > + (define (force-arrow-end fig style) + + \ \ (decorate fig "arrow-end" style #t)) + + + <\input|Scheme] > + (define (dash-style fig style) + + \ \ (decorate fig "dash-style" style #f)) + + + <\input|Scheme] > + (define (force-dash-style fig style) + + \ \ (decorate fig "dash-style" style #t)) + + + <\unfolded-io|Scheme] > + (plot (dash-style (fill (colorize (circle (point 0 0) 1) "blue") + "green") "1111010")) + <|unfolded-io> + ||>>> + + + <\unfolded-io|Scheme] > + (plot (arrow-end (line (point -2 0) (point 0 0) (point 1 1)) + "\|\gtr\")) + <|unfolded-io> + |||>>> + + + + + + 前文所作之图,我们都只是将图形对象生成出来文档树放在进程的输出上,我们观察到坐标的原点就在文档横截线的中点上。用光标选中这个图案,可以看到左边的一大截空白。在上一节作出的箭头图案前输入了单词left后,你可以清晰地看到这些空白。 + + left|||>> + + 由此可以知道,在没有画布的情况下,会分配一个动态大小的画布,以适应图形的尺寸。 + + 前文中的图像都只是单个图形对象在默认画布上的显示。引入画布之后,我们就可以将多个图形对象叠加在同一个画布上。通过逆向工程<\footnote> + 方法请参考附录中的小贴士 + ,可以举出这个例子: + + <\session|scheme|default> + <\input|Scheme] > + (define (graphics . objects) + + \ \ (cond ((nlist? objects) '(graphics "" "")) + + \ \ \ \ \ \ \ \ ((== objects '()) '(graphics "" "")) + + \ \ \ \ \ \ \ \ (else `(graphics "" ,@objects)))) + + + <\input|Scheme] > + (define (geometry fig x y) + + \ \ (decorate fig "gr-geometry" `(tuple "geometry" ,x ,y "center") #f)) + + + <\unfolded-io|Scheme] > + (plot (geometry (graphics\ + + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (fill (rectangle (point -2 -1) (point + 1 1)) "blue") + + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (fill (rectangle (point -1 -1) (point + 2 1)) "red") + + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (dash-style (line (point 1 -1) (point + 1 1)) "11100")) + + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "5cm" "3cm")) + <|unfolded-io> + ||||>>||||>>||>>>>> + + + + 现在我们就能够用函数,将多个图形对象叠加在同一个画布上,而且,图形对象的顺序决定了渲染的顺序,后者会覆盖前者。如上图所示,虚线表示原来蓝色矩形的右边界,现在被红色矩形覆盖了。 + + 而函数可以控制画布的大小。注意,前文中都没有讨论长度单位这一因素。但实际上前文中所有的坐标的单位都是。所以在指定画布的宽度和高度的时候,我们需要加上这个单位,因为这里的默认单位不是。 + + 另外,我们还可以剪裁画布,尽可能减少画布周围的空白。 + + <\session|scheme|default> + <\input|Scheme] > + (define (crop fig) + + \ \ (decorate fig "gr-auto-crop" "true" #f)) + + + <\unfolded-io|Scheme] > + (plot (crop (graphics\ + + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (fill (rectangle (point -2 -1) (point + 1 1)) "blue") + + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (fill (rectangle (point -1 -1) (point + 2 1)) "red") + + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (dash-style (line (point 1 -1) (point + 1 1)) "11100")))) + <|unfolded-io> + |||>>||||>>||>>>>> + + + + 选中最近的这两个一样的图像,你就可以看到区别。 + + + + 这一章主要利用前文定义好的函数,绘制各种各样有趣的图案。 + + + + 将半径为R的圆周n等分,然后用直线将各个等分点两两相连。 + + + + 将半径为>的圆周n等分,然后以每个等分点为圆心,以>为半径画n个圆。 + + + + + + + + + + + + > + + + + and triangle<\footnote> + + > + + + + > + + + + + + 表达式求值> + + 当你刚刚用编辑器打开本文时,如果你跳到中间的某节去执行代码,很有可能会出错,因为当前的代码很有可能依赖上前文中已经出现过的函数和变量。而将前文中所有的代码都执行一遍这个操作实际上非常繁琐。启用,将光标置于本文的某个进程中,然后就可以导出所有的代码到单个文件中。然后,开启一个进程并输入,回车之后,文中所有的代码就都被加载了。 + + + + + + <\itemize> + A TeXmacs graphics tutorial<\footnote> + + , by Henri Lesourd. + + Turtle schemes<\footnote> + + , by Ana Caizares Garca and Miguel de Benito Delgado + + Fractal turtles<\footnote> + + , by Ana Caizares Garca and Miguel de Benito Delgado + + + \; + + +<\initial> + <\collection> + + + + +<\references> + <\collection> + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + + + +<\auxiliary> + <\collection> + <\associate|idx> + |插入>||会话>||Scheme>>|> + + |帮助>||用户手册>||内置作图工具>>|> + + |工具>||开发菜单>>|> + + |开发者>||Export + Sessions...>>|> + + |转到>||无标题文件>>|> + + <\associate|table> + |1>|> + \; + |> + + |2>||部分对象属性>|> + + <\associate|toc> + 1简介 |.>>>>|> + + + 2基本原理 |.>>>>|> + + + |2.1原语 + |.>>>>|> + > + + |2.2操纵样式属性 + |.>>>>|> + > + + |2.3摆弄画布 + |.>>>>|> + > + + 3画廊 |.>>>>|> + + + |3.1金刚石图案 + |.>>>>|> + > + + |3.2圆环图案 + |.>>>>|> + > + + |3.3肾形图案 + |.>>>>|> + > + + |3.4心脏形图案 + |.>>>>|> + > + + |3.5分形图案 + |.>>>>|> + > + + |3.5.1树 + |.>>>>|> + > + + |3.5.2Koch + snowflake|7><\float|footnote|> + ||par-left||par-right||font-shape||dummy||dummy||<\surround|||>|7>. + ||7>>> + ||>||language||https://en.wikipedia.org/wiki/Koch_snowflake>> + >> + |>> + |.>>>>|> + > + + |3.5.3Sierpinski + carpet|10><\float|footnote|> + ||par-left||par-right||font-shape||dummy||dummy||<\surround|||>|10>. + ||10>>> + ||>||language||https://en.wikipedia.org/wiki/Sierpinski_carpet>> + >> + |>> + and triangle|11><\float|footnote|> + ||par-left||par-right||font-shape||dummy||dummy||<\surround|||>|11>. + ||11>>> + ||>||language||https://en.wikipedia.org/wiki/Sierpinski_triangle>> + >> + |>> + |.>>>>|> + > + + |3.5.4Mandelbrot + set|16><\float|footnote|> + ||par-left||par-right||font-shape||dummy||dummy||<\surround|||>|16>. + ||16>>> + ||>||language||https://en.wikipedia.org/wiki/Mandelbrot_set>> + >> + |>> + |.>>>>|> + > + + 4附录 |.>>>>|> + + + |4.1小贴士 + |.>>>>|> + > + + |4.1.1对本文所有的|Scheme>表达式求值 + |.>>>>|> + > + + |4.1.2逆向工程 + |.>>>>|> + > + + |4.2参考资料 + |.>>>>|> + > + + + \ No newline at end of file diff --git a/墨干编辑器/index.tm b/墨干编辑器/index.tm index f43a225..1e63938 100644 --- a/墨干编辑器/index.tm +++ b/墨干编辑器/index.tm @@ -1,4 +1,4 @@ - + > @@ -15,6 +15,8 @@ <\itemize> + +