树图形规则
const Tree = {
// 基态 --> 最初的形态
start: "F",
// 裂变规则
rules: { F: "F[+F]F[-F][F]" },
}
- 第 0 次裂变
F - 第 1 次裂变
F按照裂变规则为F[+F]F[-F][F] - 第 2 次裂变
F[+F]F[-F][F]-->F[+F]F[-F][F][+F[+F]F[-F][F]]F[+F]F[-F][F][-F[+F]F[-F][F]][F[+F]F[-F][F]]
树图形绘制规则
const drawRules = {
angle: -Math.PI / 2, // 旋转角度记录,起始角度
len: 12, // 一格距离
x: windows.innerWidth / 2, // 起点 X 位置
y: windows.innerHeight + 10, // 起点 Y 位置
rotate: (20 * Math.PI) / 180, // 旋转叠加角度
actions: {
"-": "left",
"+": "right",
F: "forward",
"[": "push",
"]": "pop",
}, // 行动规则
}
| 符号 | 意义 |
|---|---|
| - | 左转 |
| + | 右转 |
| F | 前进一格 |
| [ | 入栈 |
| ] | 出栈 |
裂变获得对应的字符串,根据绘制规则 —— 设定起点(x,y)和方向(angle),从左到右扫描字符串,遇到 F 就前进一格,遇到 - 向左旋转 20°,遇到 + 向右旋转 20°,这样就得到一棵树。
裂变代码实现
裂变的规则没有变化。
/**
* 裂变
*
* @param graph 图形
* @param times 裂变次数
* @return
*/
function replacement(graph, times) {
let { start, rules } = graph
for (let i = 0; i < times; i++) {
let temp = ""
for (let j = 0; j < start.length; j++) {
const s = start[j]
if (Object.keys(rules).includes(s)) {
temp += rules[s]
} else {
temp += s
}
}
start = temp
}
return start
}
图形绘制代码实现
图形绘制需处理枝叶的入栈和出栈。
/**
* 图形绘制规则
*
* @param str 裂变后字符串
* @return 图形点[[[x],[y]], [[x],[y]]]三维数组
*/
function interpretation(str, drawRules) {
let { actions, rotate, angle, len, x, y } = drawRules,
point_x = [x],
point_y = [y],
coordinates = [[point_x, point_y]],
stack = []
for (let i = 0; i < str.length; i++) {
const s = str[i]
if (!Object.keys(actions).includes(s)) {
continue
} else if (actions[s] === "left") {
angle -= rotate
} else if (actions[s] === "right") {
angle += rotate
} else if (actions[s] === "forward") {
const next_x = point_x[point_x.length - 1] + len * Math.cos(angle),
next_y = point_y[point_y.length - 1] + len * Math.sin(angle)
point_x.push(next_x)
point_y.push(next_y)
} else if (actions[s] === "push") {
stack.push([
angle,
point_x[point_x.length - 1],
point_y[point_y.length - 1],
])
} else if (actions[s] === "pop") {
const cur = stack.pop(),
stackAngle = cur[0],
_x = cur[1],
_y = cur[2]
point_x = [_x]
point_y = [_y]
angle = stackAngle
coordinates.push([point_x, point_y])
}
}
return coordinates
}
绘制代码实现
/**
* 绘制
*
* @param points 图形点[[[x],[y]], [[x],[y]]]三维数组
* @param canvas = "canvas" 元素选择器
*/
function draw(points, canvas = "canvas") {
const ctx = document.querySelector(canvas).getContext("2d")
ctx.strokeStyle = "rgba(100, 125, 100, 0.2)"
ctx.beginPath()
let count = 0
for (let i = 0; i < points.length; i++) {
const point = points[i]
for (let j = 0; j < point[0].length; j++) {
ctx.lineTo(point[0][j], point[1][j])
}
}
ctx.stroke()
}