2.1 题目描述
绘制一个简单的分形树,如图2.1:
图2.1 分形树
先垂直绘制一根线段,然后在线段顶端向右一定倾角绘制一根线段,长度分别为原线段的k倍,再同样的,在线段左侧以固定倾角绘制一根线段,如此反复,直至线段长度小于某个较小的值。其中,线条颜色以及长度粗细,夹角(例如产 生某个范围的随机数)都可以自行进行微调。
2.2 程序使用说明
- 启动程序;
2. 等待树枝绘制完成。2.3 分析和设计
- 思路
绘制一条树枝需要知道树枝的起点、偏角以及长度。树枝的起点为枝干的终点,右树枝的的偏角为枝干偏角减去左右树枝夹角的一半,左树枝的偏角为枝干偏角加上左右树枝夹角的一半。左右树枝绘制完成后,再以当前左右树枝为枝干绘制它们的树枝,直到树枝足够短。
2. 伪代码GenerateTree(startX, startY, angle, length)// 输入:树枝的起点startX、startY,枝干的偏角angle,树枝长度length// 输出:分形树// 随机产生一个角度作为左右树枝夹角的一半randAngle <- randam()leftEndX <- startX + cos((angle+randAngle)/180*PI)*length*0.8// 向上的y值较小leftEndY <- startY - sin((angle+randAngle)/180*PI)*length*0.8// 绘制树枝draw(startX, startY, leftEndX, leftEndY)GenerateTree(leftEndX, leftEndY, angle+randAngle, length*0.8)rightEndX <- startX + cos((angle-randAngle)/180*PI)*length*0.8// 向上的y值较小rightEndY <- startY - sin((angle-randAngle)/180*PI)*length*0.8// 绘制树枝draw(startX, startY, rightEndX, rightEndY)GenerateTree(rightEndX, rightEndY, angle-randAngle, length*0.8)
- 时间复杂度
分开树是一棵二叉树,所以时间复杂度为O(2n)。2.4 测试用例
测试效果如图2.1所示。
图2.1 分形树2.5 源代码(含注释)
import javafx.application.Application;import javafx.application.Platform;import javafx.scene.Scene;import javafx.scene.layout.Pane;import javafx.scene.paint.Color;import javafx.scene.shape.Line;import javafx.stage.Stage;import java.util.Random;public class FractalTree extends Application {private Pane tree;@Overridepublic void start(Stage primaryStage) throws Exception {tree = new Pane();double length = 100.0;int startX = 500;int startY = 600;double stokeWidth = 15;Line line = new Line(startX, startY, startX, startY-length);line.setStrokeWidth(stokeWidth);line.setStroke(Color.valueOf("rgb(0,0,0)"));tree.getChildren().add(line);Scene scene = new Scene(tree, startX*2, startY);primaryStage.setScene(scene);primaryStage.show();generateBranch(length, startX, startY-length, 90, stokeWidth*0.8, 0);}/*** 画树枝* @param length 树枝长度* @param startX 树枝的起始X坐标* @param startY 树枝的起始X坐标* @param angle 当前枝干的偏角* @param strokeWidth 宽度*/private void generateBranch(double length, double startX, double startY, double angle, double strokeWidth, int red){if (red > 255){red = 255;}if (length < 8){return ;}// 15度以上的开角,以枝干为轴,各树枝偏移一半double randAngle = (15+new Random(System.currentTimeMillis()).nextInt(60))/2;double rightEndX = startX+Math.cos((angle-randAngle)/180*Math.PI)*length;double rightEndY = startY-Math.sin((angle-randAngle)/180*Math.PI)*length;Line right = new Line(startX, startY, rightEndX, rightEndY);right.setStrokeWidth(strokeWidth);right.setStroke(Color.valueOf("rgb("+red+",0,0)"));int finalRed = red;new Thread(() -> {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}Platform.runLater(() -> tree.getChildren().add(right));generateBranch(length*0.8, rightEndX, rightEndY, angle-randAngle, strokeWidth*0.8, finalRed+15);}).start();double leftEndX = startX+Math.cos((angle+randAngle)/180*Math.PI)*length;double leftEndY = startY-Math.sin((angle+randAngle)/180*Math.PI)*length;Line left = new Line(startX, startY, leftEndX, leftEndY);left.setStrokeWidth(strokeWidth);left.setStroke(Color.valueOf("rgb("+red+",0,0)"));new Thread(() -> {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}Platform.runLater(() -> tree.getChildren().add(left));generateBranch(length*0.8, leftEndX, leftEndY, angle+randAngle, strokeWidth*0.8, finalRed+15);}).start();}public static void main(String[] args) {launch(args);}}
