希尔伯特曲线矩阵与动画

在这里插入图片描述

在这里插入图片描述

在上一篇中是通过缩小,旋转图形实现希尔伯特曲线,会受到整型运算干扰。这次将使用矩阵存储每个点的序号,完全避免整型运算的影响。

希尔伯特曲线矩阵

一阶希尔伯特曲线矩阵
在这里插入图片描述

二阶希尔伯特曲线矩阵

在这里插入图片描述
将二阶希尔伯特曲线矩阵分为4个象限

在这里插入图片描述
能观察到4个象限的与一阶希尔伯特曲线矩阵有较大关系。
比如第3象限为一阶希尔伯特曲线矩阵关于对角线 0,2对称或逆时针旋转90度
第2象限为一阶希尔伯特曲线矩阵加4 (4=前一阶矩阵的元素个数)
第1象限为一阶希尔伯特曲线矩阵加4 后乘以2
第4象限为一阶希尔伯特曲线矩阵加4 后乘以3 并逆时针旋转90 度,再关于水平翻转180度(用左手来比划比划:掌心向内,手指向下,弯曲拇指中指无名指,现在小拇指尖为0,食指指尖为4,活动左手,手指向右,手背向内)

这样就非常简单了,后一阶希尔伯特曲线矩阵可通过前一阶希尔伯特曲线矩阵作旋转,加法运算即可。

代码

public final class HibertPlus {
	//key为true时关于右倾对角线对称
	//key为false时行列交换
	public static int[][] transposition(int[][] array,boolean key){
		int len=array.length;
		int[][] tran = new int[len][len];
		
			for(int i=0;i<len;i++) {
				for(int j=0;j<len;j++) {
					if(key) {
				//		tran[i][j]=array[j][len-1-i];
						tran[j][i]=array[len-1-i][len-1-j];
					}else {
						tran[j][i]=array[i][j];
					}
						
				}
				
		}
		return tran;
	}
	public static void show(int[][] array) {
		int n=array.length;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                System.out.printf("%2d\t", array[i][j]);
            }
            System.out.println();
        } System.out.println();
	}
    public static int[][] up(int[][] old) {
    	int len=old.length;
    	int n=0;
    	while(1<<n<len)n++;
    	int value=(int) Math.pow(4, n);
    	int[][] array = new int[2*len][2*len];
    	//第3象限
    	int[][] three=transposition(old,true);
        for (int i = 0; i < len; i++) {
            for (int j = 0; j < len; j++) {
            	array[i+len][j]=three[i][j];
            }
        }
    	//第4象限
    	int[][] four=transposition(old,false);
        for (int i = 0; i < len; i++) {
            for (int j = 0; j < len; j++) {
            	array[i+len][j+len]=four[i][j]+3*value;
            }
        }
    	//第1象限
    	int[][] one=old;
        for (int i = 0; i < len; i++) {
            for (int j = 0; j < len; j++) {
            	array[i][j+len]=one[i][j]+2*value;
            }
        }
    	//第1象限
    	int[][] two=old;
    
        for (int i = 0; i < len; i++) {
            for (int j = 0; j < len; j++) {
            	array[i][j]=two[i][j]+value;
            }
        }
    	return array;
    }
    public static int[][] get(int n){
    	int[][] array = new int[][] {{1,2},{0,3}};	
    	while(n>1) {
    		n--;
    		array=up(array);
    	}
		return array;
    }
}

测试

    	show(get(1));
    	show(get(2));
    	show(get(3));
    	//show(get(4));
    	//show(get(5));

输出

1 2
0 3

5 6 9 10
4 7 8 11
3 2 13 12
0 1 14 15

21 22 25 26 37 38 41 42
20 23 24 27 36 39 40 43
19 18 29 28 35 34 45 44
16 17 30 31 32 33 46 47
15 12 11 10 53 52 51 48
14 13 8 9 5 4 55 50 49
1 2 7 6 5 7 5 6 61 62
0 3 4 5 5 8 5 9 60 63

希尔伯特曲线动画代码

通过每隔一段时间添加一条直线达到动画效果。
要添加一条直线就得记录上一条直线的末端,如果是第一条直线就记录下来,用作下一条直线首端
如果画完了就关闭service。

public class Test extends Application {
	ScheduledService<Number> service;//任务
	int[][] array;//希尔伯特曲线矩阵
	int value=0;//序列值
	int rank=6;//阶数
	final int SIZE=600;
	AnchorPane anchorPane=new AnchorPane();
    public static void main(String[] args) {
    	launch();
    }

	@Override
	public void start(Stage primaryStage) throws Exception {
		// TODO Auto-generated method stub
		initArray();
		
	//	anchorPane.getChildren().add(view);
		initService();

		
		Scene scene=new Scene(anchorPane);
		anchorPane.setTranslateX(25);
		anchorPane.setTranslateY(25);
		primaryStage.setScene(scene);
		primaryStage.setWidth(SIZE+50);
		primaryStage.setHeight(SIZE+50);
		primaryStage.show();
	}
	public void initArray() {
		array = HibertPlus.get(rank);
		int len=array.length;
		for (int i = 0; i < len/2; i++) {
			for (int j = 0; j < len; j++) {
				int tmp=array[i][j];
				array[i][j]=array[len-1-i][j];
				array[len-1-i][j]=tmp;
			}
		}
	}
	private int oldi=0,oldj=0;
	public void line() {
		double length=SIZE/Math.pow(2, rank);
		int len=array.length;
		System.out.println(" +value "+value);
		//可改进为向四个方向搜索目标值
		for (int i = 0; i < len; i++) {
			for (int j = 0; j < len; j++) {
				if(array[i][j]==value) {
					if(oldi<-1) {
						oldi=i;
						oldj=j;
					}else {
						Line line =new Line(oldi*length,oldj*length,i*length,j*length);
						line.setStroke(Color.RED);
						anchorPane.getChildren().add(line);
						oldi=i;
						oldj=j;
					}
				}
			}
		}
		value+=1;
		if(value>Math.pow(4, rank)) {
			service.cancel();
		}
	}
	public void initService() {
		service =new ScheduledService<Number>(){
			protected Task<Number> createTask() {
				Task<Number> task=new Task<Number>(){
					protected void updateValue(Number value) {
						super.updateValue(value);
						line();
					}
					protected Number call() throws Exception {
						return 0;
					}	
				};
				return task;
			}
		};
		service.setDelay(Duration.seconds(1));
		service.setPeriod(Duration.seconds(0.1));
		service.setRestartOnFailure(true);
		service.setMaximumFailureCount(4);
		service.start();
		anchorPane.setOnMouseClicked(e->{
			service.cancel();
		});
	}
}

在这里插入图片描述

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值