通过脚本可以为 SketchUp 设计增加自动化、动画和几何计算。如果可以编写适当的代码,SketchUp 可以成为像 Maya 这样的呈现工具或者像 AutoCAD 这样的机械设计工具。本文是一个分两部分的 “用 SketchUp 和 Eclipse 进行 3D 建模” 系列的第 2 部分,文中描述 SketchUp 脚本中使用的众多基本类,并提供一些例子来展示这些类的用法。通过这些类,可以使用线段和面构造任意的 3D 图形。然后,可以用颜色和图像配置每个面的外观。
第 1 部分 展示如何设置 Eclipse 环境,以便创建、编辑和执行 SketchUp 脚本。这个部分提供了一个示例脚本,但是留下一个重要的问题没有回答:脚本中的代码是如何工作的?本文的目的是通过讨论 SketchUp API 来回答这个问题。SketchUp API 包含一些类,这些类的方法可以绘制和修改 SketchUp 设计的一些方面,包括直线、面、颜色和图像。本文无法涵盖整个 API,所以我重点关注构造 SketchUp 形状所需的基本的类。但是,由于 SketchUp API 是基于 Ruby 的,因此,我将首先概述什么是 Ruby 语言以及它是如何工作的。
|
面向 Java 程序员的 Ruby 简介
考虑到 Java™ 编程语言的流行度,加上本文提到了 Eclipse,我假设您熟悉 Java 编程语言。而 Ruby 则没有那么流行,因此我简要地解释一下两者之间的相似点和不同点。希望这种方式能让您对该语言有足够的了解,并试着编写一些基本的命令。
分析:
- 和 Java 语言一样,Ruby 是面向对象的。实际上,Ruby 中的所有 内容都是 Object 的子类。Ruby 不具备 Java 语言中的 int、 float 和 boolean 这样的基本类型。
- 在 Ruby 中不必声明变量类型,所以可以在一个命令中将 x 设为等于 5,而在下一个命令中又可以将 x 设为等于 “Hello world!”。
- 和 Java 编程一样,Ruby 方法也是通过点标记法调用的,但是括号(())和分号(;)是可选的。每个 Ruby 类有一个名为 new 的构造函数方法。
- Ruby String 对象可以用双引号(")括起来,也可以用单引号(')括起来;不同之处是,解释器可以识别双引号括起的 String 对象中的转义序列(\n、 \t 等)。Ruby 接受单字符 String 对象,但是没有单独用于 char 对象的数据结构。
- 单行注释以 # 开头。多行注释由 =begin 和 =end 分隔。
- Ruby 类与 Java 类的作用类似,但是除了类以外,Ruby 还支持 模块。Ruby 模块就像只包含静态方法的 Java 类。Ruby 模块不能实例化;它只是一个不同的名称空间下的例程的集合。
- 最常见的文本输出方法有 puts 和 print,前一个方法在输出的末端增加一个换行符,后一个方法则不是。
记住这些规则后,就可以开始尝试编写 Ruby 代码。在 SketchUp 中,单击 Window > Ruby Console。然后尝试以下任何一个命令或所有的命令:
- 2 * (5 + 5) / 4 * 1.0
- 6.class
- print 'Hello world'; puts '!'
- m = Time.new; m.month
- x = [4, true, 'hi there!']
- puts x[2].to_s + " is a " + x[2].class.to_s
在最后一个命令中,Ruby 的 Object 类的 to_s 方法执行类似 Java 的 Object 类的 toString() 方法的操作:它返回一个表示 Object 的 String。图 1 展示了 SketchUp 的 Ruby Console 中显示的这些命令的结果。
图 1. Ruby Console 中的输出
这些命令也许看起来比较简单,但 Ruby 提供了一些独特的特性,这些特性在 Java、C 或 C++ 语言中完全找不到。这些独特的特性包括 iterator 块、并行赋值和像 Range 类这样奇妙的东西。但是说到 SketchUp API,只需对该语言有基本的理解,就可以做很多事情。下一节详细讨论该 API。
SketchUp API
第 1 部分提供了一个示例 SketchUp 脚本,并解释了如何使用 SketchUp 的 load 命令和 SketchUp Bridge 执行它。但是文章中没有解释脚本是如何工作的。该脚本的命令是 SketchUp API 的一部分 — 这正是本节的主题。我首先给出基本的 SketchUp 数据结构(Sketchup 和 Model),然后解释如何创建 Edge 和 Face 对象。然后,我解释两个挤压(extrusion)方法 — pushpull 和 followme — 最后描述如何将 SketchUp 材质(material)内容应用到对象。
基本数据结构
Ruby 模块是方法的集合;SketchUp 模块是 SketchUp API 中最重要的模块。它的方法提供与整个 SketchUp 安装相关的信息,下面列出其中 5 个方法:
- os_language — 返回运行 SketchUp 的操作系统
- locale — 返回当前位置的语言代码
- find_support_files — 返回顶级 SketchUp 目录中文件的路径
- version_number — 返回 SketchUp 的版本
- active_model — 返回表示当前设计的 Model 对象
与 Java 语言中任何静态方法一样,Ruby 模块方法的调用方式是在模块名后加一个点再加方法名。例如,为了发现 SketchUp 应用程序的版本,可以在 Ruby Console 中输入以下命令:Sketchup.version_number。
在 SketchUp 模块中的所有方法当中,active_model 是最重要的。它返回 Model 对象,其中包含当前 SketchUp 设计中的所有信息。每个设计只有一个 Model 对象,每个 Model 对象只包含一个设计。这里的 “所有信息” 是指 Model 对象存储每个顶点的位置、每个形状的颜色、可用于设计的风格等。Model 将信息存储在一系列的容器对象(container object) 中,包括:
- Entities — 当前设计中的所有形状
- Materials — 颜色和纹理(texture)
- Layers — 设计的图层
- Styles — 设计的显示设置
一般而言,SketchUp 脚本的目的是修改这些容器对象中的数据。为此,可调用 Model 类中相应的方法。这些方法非常容易记住:layers 方法返回 Layers 对象,styles 方法返回 Styles 对象,entities 方法返回 Entities 对象,依此类推。例如,下面的代码获取当前 Model 对象的 Entities 容器:
model = Sketchup.active_model ents = model.entities |
可以将这些代码合并到一个命令中:
ents = Sketchup.active_model.entities |
这是必须知道的一个重要命令,因为本文中的所有示例脚本都以这一行开头。您可以 下载 这些示例脚本。接下来,我将解释为什么能够访问 Model 对象的 Entities 容器是如此重要。
SketchUp 实体:Edges 和 Faces
如您所料,Entities 容器包含 Entity 对象。简言之,一个 Entity 对象表示 SketchUp 设计窗口中任何可以看见、移动或修改的形状。Entity 类是 SketchUp 中很多类的超类,如图 2 所示,该图显示了大部分 Entity 子类。
图 2. Entity 类的层次结构
最重要的 Entity 对象是 Edge 和 Face 对象,这两个对象可作为 SketchUp 设计中的任何形状的构建块。Edge 是一条线段,可以通过 Entities 类的 add_line 方法将 Edge 对象添加到设计中。该方法接受两个各有 3 个元素的数组,这两个数组分别表示 Edge 对象的起点和终点。例如,要创建一条从 [0, 0, 0] 到 [5, 5, 5] 的线段,可以使用下面这样的代码:
ents = Sketchup.active_model.entities edge = ents.add_line [0,0,0], [5, 5, 5] |
当第二条命令执行时,SketchUp 自动在设计窗口中画出与 Edge 对象对应的直线。可以通过调用 Edge 类的方法查看和修改直线的属性。例如,length 方法返回直线的长度,start 返回起始点,end 返回终点。还有 smooth 和 hidden 之类的方法可用于改变直线的外观。
顾名思义,Face 对象表示一个 2-D 平面。Entities 类的 add_face 方法在设计窗口中画出该平面,并返回一个 Face 对象。该方法接受一组点或 Edge 对象为参数。例如,下面的代码创建两个 Face 对象 — 一个在 x-y 平面上,另一个在 y-z 平面上。这两个 Face 对象都有 4 个顶点,但实际上可以创建有任意个点的 Face。
ents = Sketchup.active_model.entities # Create a face from points face1 = ents.add_face [0,0,0], [3,0,0], [3,3,0], [0,3,0] # Create a face from edges edge1 = ents.add_line [0,0,0], [0,3,0] edge2 = ents.add_line [0,3,0], [0,3,3] edge3 = ents.add_line [0,3,3], [0,0,3] edge4 = ents.add_line [0,0,3], [0,0,0] face2 = ents.add_face [edge1, edge2, edge3, edge4] |