Java语言程序设计基础篇_编程练习题**18.37 (希尔伯特曲线)

目录

题目:**18.37 (希尔伯特曲线)

代码示例

代码逻辑解释

1. 初始化与布局

2. 绘制逻辑

3. 绘制过程

输出结果


题目:**18.37 (希尔伯特曲线)

希尔伯特曲线,由德国数学家希尔伯特于1891年第一个给出描述,是一种空间填充曲线,以 2 x 2, 4 x 4, 8 x 8, 16 x 16, 或者任何其他 2 的幂的大小来访问一个方格网的每个点。编写程序,以给定的阶数显示希尔伯特曲线,如图 18-19 所示。

  • 代码示例

编程练习题18_37HilbertCurve.java

package chapter_18;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class 编程练习题18_37HilbertCurve extends Application {

    private static final int WIDTH = 700;
    private static final int HEIGHT = 700;
    private static final int MARGIN = 10;
    private double segX, segY;
    private int[] EXP = new int[10];

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        // Initialize EXP array
        EXP[0] = 1;
        for (int i = 1; i < 10; i++) {
            EXP[i] = EXP[i - 1] * 2;
        }

        // Create UI components
        Label lblOrder = new Label("Enter the order: ");
        TextField txtOrder = new TextField();
        Canvas canvas = new Canvas(WIDTH, HEIGHT);
        GraphicsContext gc = canvas.getGraphicsContext2D();

        // Layout
        HBox hBox = new HBox(lblOrder, txtOrder);
        hBox.setAlignment(Pos.CENTER);
        VBox vBox = new VBox(canvas,hBox);

        // Event handler for the button
        txtOrder.setOnKeyPressed(event -> {
        	if(event.getCode() == KeyCode.ENTER&&event.getText() != "") {
        		try {
            		int order = Integer.parseInt(txtOrder.getText());
            		if (order > 0 && order < 10) {
            			gc.clearRect(0, 0, WIDTH, HEIGHT);
            			segX = (WIDTH - 2 * MARGIN) / (EXP[order] - 1.0);
            			segY = (HEIGHT - 2 * MARGIN) / (EXP[order] - 1.0);
            			showOrder(0, 0, 1, order, gc);
            		}
        		} catch (NumberFormatException e) {
        			//System.out.println("Please enter a valid integer.");
        			System.out.println(e);
        		}
        	}
        });

        // Scene and stage setup
        Scene scene = new Scene(vBox);
        primaryStage.setTitle(getClass().getName());
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void showOrder(int startX, int startY, int shape, int order, GraphicsContext gc) {
        if (order == 1) {
            switch (shape) {
                case 1:
                    drawLine(gc, startX, startY, startX, startY + 1);
                    drawLine(gc, startX, startY + 1, startX + 1, startY + 1);
                    drawLine(gc, startX + 1, startY + 1, startX + 1, startY);
                    break;
                case 2:
                    drawLine(gc, startX, startY, startX + 1, startY);
                    drawLine(gc, startX + 1, startY, startX + 1, startY + 1);
                    drawLine(gc, startX + 1, startY + 1, startX, startY + 1);
                    break;
                case 3:
                    drawLine(gc, startX, startY + 1, startX, startY);
                    drawLine(gc, startX, startY, startX + 1, startY);
                    drawLine(gc, startX + 1, startY, startX + 1, startY + 1);
                    break;
                case 4:
                    drawLine(gc, startX + 1, startY, startX, startY);
                    drawLine(gc, startX, startY, startX, startY + 1);
                    drawLine(gc, startX, startY + 1, startX + 1, startY + 1);
                    break;
            }
        } else {
            switch (shape) {
                case 1:
                    showOrder(startX, startY, 2, order - 1, gc);
                    drawLine(gc, startX, startY + EXP[order - 1] - 1, startX, startY + EXP[order - 1]);
                    showOrder(startX, startY + EXP[order - 1], 1, order - 1, gc);
                    drawLine(gc, startX + EXP[order - 1] - 1, startY + EXP[order - 1], startX + EXP[order - 1], startY + EXP[order - 1]);
                    showOrder(startX + EXP[order - 1], startY + EXP[order - 1], 1, order - 1, gc);
                    drawLine(gc, startX + EXP[order] - 1, startY + EXP[order - 1], startX + EXP[order] - 1, startY + EXP[order - 1] - 1);
                    showOrder(startX + EXP[order - 1], startY, 4, order - 1, gc);
                    break;
                case 2:
                    showOrder(startX, startY, 1, order - 1, gc);
                    drawLine(gc, startX + EXP[order - 1] - 1, startY, startX + EXP[order - 1], startY);
                    showOrder(startX + EXP[order - 1], startY, 2, order - 1, gc);
                    drawLine(gc, startX + EXP[order - 1], startY + EXP[order - 1] - 1, startX + EXP[order - 1], startY + EXP[order - 1]);
                    showOrder(startX + EXP[order - 1], startY + EXP[order - 1], 2, order - 1, gc);
                    drawLine(gc, startX + EXP[order - 1] - 1, startY + EXP[order] - 1, startX + EXP[order - 1], startY + EXP[order] - 1);
                    showOrder(startX, startY + EXP[order - 1], 3, order - 1, gc);
                    break;
                case 3:
                    showOrder(startX, startY + EXP[order - 1], 2, order - 1, gc);
                    drawLine(gc, startX, startY + EXP[order - 1], startX, startY + EXP[order - 1] - 1);
                    showOrder(startX, startY, 3, order - 1, gc);
                    drawLine(gc, startX + EXP[order - 1] - 1, startY + EXP[order - 1] - 1, startX + EXP[order - 1], startY + EXP[order - 1] - 1);
                    showOrder(startX + EXP[order - 1], startY, 3, order - 1, gc);
                    drawLine(gc, startX + EXP[order] - 1, startY + EXP[order - 1] - 1, startX + EXP[order] - 1, startY + EXP[order - 1]);
                    showOrder(startX + EXP[order - 1], startY + EXP[order - 1], 4, order - 1, gc);
                    break;
                case 4:
                    showOrder(startX + EXP[order - 1], startY, 1, order - 1, gc);
                    drawLine(gc, startX + EXP[order - 1], startY, startX + EXP[order - 1] - 1, startY);
                    showOrder(startX, startY, 4, order - 1, gc);
                    drawLine(gc, startX + EXP[order - 1] - 1, startY + EXP[order - 1] - 1, startX + EXP[order - 1] - 1, startY + EXP[order - 1]);
                    showOrder(startX, startY + EXP[order - 1], 4, order - 1, gc);
                    drawLine(gc, startX + EXP[order - 1] - 1, startY + EXP[order] - 1, startX + EXP[order - 1], startY + EXP[order] - 1);
                    showOrder(startX + EXP[order - 1], startY + EXP[order - 1], 3, order - 1, gc);
                    break;
            }
        }
    }

    private void drawLine(GraphicsContext gc, int x1, int y1, int x2, int y2) {
        gc.strokeLine(MARGIN + x1 * segX, MARGIN + y1 * segY, MARGIN + x2 * segX, MARGIN + y2 * segY);
    }
}
  • 代码逻辑解释

1. 初始化与布局
  • 变量初始化:定义了一些常量(如窗口的宽度和高度、边距等)和数组EXP,用于存储2的幂次方值,方便后续计算。
  • UI组件创建:创建了一个文本输入框(TextField)用于输入阶数,一个标签(Label)用于提示用户输入,一个画布(Canvas)用于绘制曲线,以及相关的布局组件(HBoxVBox)。
  • 事件处理:为文本输入框设置了一个键盘事件监听器,当用户按下回车键并且输入的内容是有效的整数时,会根据输入的阶数来绘制希尔伯特曲线。
2. 绘制逻辑
  • showOrder方法:这是绘制希尔伯特曲线的核心方法,它根据阶数(order)和当前绘制的形状(shape,用1到4表示四种不同的递归方向)来递归地绘制曲线。当阶数为1时,直接绘制基础的四段直线;当阶数大于1时,根据递归规则和当前形状来决定下一步的绘制方向和位置。

  • 递归规则:对于每个阶数大于1的情况,showOrder方法会根据当前的shape值选择一种递归模式,每种模式都会先递归绘制子曲线,然后绘制连接子曲线的线段,最后继续递归绘制其他子曲线。这种递归模式确保了曲线能够填充整个二维空间,并且保持了曲线的连续性。

  • drawLine方法:这是一个辅助方法,用于在画布上绘制线段。它接收线段的起点和终点坐标,然后考虑到边距和当前阶数的线段长度(segXsegY),计算出实际绘制时的坐标,并使用GraphicsContext对象的strokeLine方法来绘制线段。

3. 绘制过程
  • 当用户输入阶数并按下回车键时,程序会首先验证输入的有效性,然后根据输入的阶数初始化线段长度(segXsegY),这两个值用于计算实际绘制时线段的像素长度。
  • 接着,程序会调用showOrder方法来开始绘制曲线。在绘制过程中,会根据递归规则和当前形状逐步绘制出整个希尔伯特曲线。
  • 每次递归调用都会将画布上的已绘制内容缩小到当前子曲线的范围,并通过调整坐标来确保子曲线能够正确地绘制在父曲线的指定位置。

  • 输出结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值