希尔伯特曲线 java_分形的乐趣之_Hilbert曲线
作者:路缘
德国数学家David Hilbert发现了一种曲线,首先把一个正方形等分成四个小正方形,依次从西南角的正方形中心出发往北到西北正方形中心,再往东到东北角的正方形中心,再往南到东南角正方形中心,这是一次迭代,如果对四个小正方形继续上述过程,往下划分,反复进行,最终就得到一条可以填满整个正方形的曲线,这就是Hibert曲线,其大致过程如下图所示
Hibert曲线生成过程
下面我们来看如何写程序生成这样的曲线,其实不管迭代多少次,都是由如下的图形
基本图
构成,唯一所不同的是开口方向不一样。开口方向不一样就涉及到图像旋转,图像旋转的基本知识接下来会介绍。目前我们最关心的是这样生成的曲线过程右什么规律,从上述描述生成的过程就已经看出了规律,当然人肯定一眼就看出来了,但计算机如何知道呢?这就是生成Hibert曲线算法的关键了:
为了便于找出规律,我们来看下面一副图
上图中应该是把所有开口方向(共四种)都涵盖了。我们约定四种类型:
开口往南-0,开口往西-1,开口往北-2,开口往东-3。我们结合基本图,就有这样的规律,画表如下:
点
点所在图类型
以该点为中心产生的图类型
dot1
0
1
dot1
1
2
dot1
2
3
dot1
3
0
其他的点类似也有类似的规律,这个规律才是我们编码的基础。是下次递归调用画图函数传参数的前提。下面我们来看一下画图中涉及到的图像旋转的相关数学知识。
图像旋转
图像旋转是指把定义的图像绕某一点以逆时针或顺时针方向旋转一定的角度,通常是指绕图像的中心以逆时针方向旋转。
假设图像的左上角为(left, top),右下角为(right, bottom),则图像上任意点(x0, y0)绕其中心(xcenter, ycenter)逆时针旋转angle角度后,新的坐标位置(x′, y′)的计算公式为:
xcenter = (right - left + 1) / 2 + left;
ycenter = (bottom - top + 1) / 2 + top;
x′ = (x0 - xcenter) cosθ - (y0 - ycenter) sinθ + xcenter;
y′ = (x0 - xcenter) sinθ + (y0 - ycenter) cosθ + ycenter;
与图像的镜像变换相类似,也采用按行逐点变换的方式实现图像的旋转。
现在一切都准备就绪,我们来实现相关的算法如下:
/**//**********************************************************************************************
功能:实现绘制Hilbert曲线
参数:
pDC:设备上下文
n:维都
len:边长
x:中心横坐标
y:中心纵坐标
iType:绘画类型,开口:0-南,1-西,2-北,3-东
unit_length:最小单元长度
/**********************************************************************************************/voidCGraphicAppView::DrawHilbert(CDC*pDC,intn,intlen,intx,inty,intiType,intunit_length)
{
//存储以x,y为中心的西南、西北、东北、东南四角定点的坐标intarr[4][2];
arr[0][0]=x-len/4; arr[0][1]=y+len/4;
arr[1][0]=x-len/4; arr[1][1]=y-len/4;
arr[2][0]=x+len/4; arr[2][1]=y-len/4;
arr[3][0]=x+len/4; arr[3][1]=y+len/4;
//存储以x,y为中心的(西南、西北、东北、东南四角定点)经过处理后的坐标inta[4][2];
memset(a,0,sizeof(a));
intsin_v=0,cos_v=1;//默认为0度的值switch(iType)//根据不同的开口方向,对旋转三角函数赋值
{
case1://开口向左sin_v=1; cos_v=0;
break;
case2://开口向上sin_v=0; cos_v=-1;
break;
case3://开口向右sin_v=-1; cos_v=0;
break;
}
for(inti=0; i<4; i++)//完成旋转
{
a[i][0]=(arr[i][0]-x)*cos_v-(arr[i][1]-y)*sin_v+x;
a[i][1]=(arr[i][0]-x)*sin_v+(arr[i][1]-y)*cos_v+y;
}
CPen newPen(PS_DASHDOTDOT,2, RGB(y%255, x%255, (y+x)%255));
pDC->SelectObject(&newPen);
if(n>1)
{
intlength=len/2;
DrawHilbert(pDC, n-1, length, a[0][0], a[0][1], (1+iType)%4,unit_length);
DrawHilbert(pDC, n-1, length, a[1][0], a[1][1], iType,unit_length);
DrawHilbert(pDC, n-1, length, a[2][0], a[2][1], iType,unit_length);
DrawHilbert(pDC, n-1, length, a[3][0], a[3][1], (3+iType)%4,unit_length);
switch(iType)
{
case0:
case2:
pDC->MoveTo(x-length+0.5*unit_length, y+0.5*unit_length);
pDC->LineTo(x-length+0.5*unit_length, y-0.5*unit_length);
pDC->MoveTo(x-0.5*unit_length, y-(1-iType)*0.5*unit_length);
pDC->LineTo(x+0.5*unit_length, y-(1-iType)*0.5*unit_length);
pDC->MoveTo(x+length-0.5*unit_length, y+0.5*unit_length);
pDC->LineTo(x+length-0.5*unit_length, y-0.5*unit_length);
break;
case1:
case3:
pDC->MoveTo(x-0.5*unit_length, y-length+0.5*unit_length);
pDC->LineTo(x+0.5*unit_length, y-length+0.5*unit_length);
pDC->MoveTo(x+(2-iType)*0.5*unit_length, y-0.5*unit_length);
pDC->LineTo(x+(2-iType)*0.5*unit_length, y+0.5*unit_length);
pDC->MoveTo(x-0.5*unit_length, y+length-0.5*unit_length);
pDC->LineTo(x+0.5*unit_length, y+length-0.5*unit_length);
break;
} }else
{
pDC->MoveTo(a[0][0], a[0][1]);
pDC->LineTo(a[1][0], a[1][1]);
pDC->LineTo(a[2][0], a[2][1]);
pDC->LineTo(a[3][0], a[3][1]);
}}
算法中还涉及到了,连接迭代产生的图像的过程,由于算法不是很优雅,在这儿就不细说了,其次如果把二维映射到三维,将会得到更美妙的曲线,最近忙着找工作,有时间再想了,有兴趣的朋友可以研究下三维的情况。
其次希望有朋友能有更好的算法,希望不吝赐教,先谢过了。最后我们来看一下迭代6次的一个运行结果图:
调用的代码段如下:
voidCGraphicAppView::OnDraw(CDC*pDC)
{
CGraphicAppDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(!pDoc)
return;
//TODO: add draw code for native data hereintn=6;
longt=::pow(2.0, n);
intlength=400;
intunit_length=length/t;
DrawHilbert(pDC, n, length,200,200,0, unit_length);
}
希尔伯特曲线 java_分形的乐趣之_Hilbert曲线相关推荐
- python绘制分形图基础_Python 绘制分形图(曼德勃罗集、分形树叶、科赫曲线、分形龙、谢尔宾斯基三角等)附代码...
1. 曼德勃罗集 import numpy as np import pylab as pl import time from matplotlib import cm def iter_point( ...
- 分形 java_分形(递归)
其实,刚开始学迭代和递归的时候,完全没想过用它来画图···只是知道可以用递归计算,比如1+2+3+4+5+...+100=?然后,发现可以通过不断画线画点形成各种有趣的图形. 1.开始画的是利用一个点 ...
- python基于模型对测试集和训练集的预测概率结果文件可视化模型的校准曲线、多个模型的校准曲线(calibration curve)
python基于模型对测试集和训练集的预测概率结果文件可视化模型的校准曲线.多个模型的校准曲线(calibration curve) 目录
- R语言使用for循环绘制多个模型的DCA(Decision Curve Analysis)曲线并保存特定分辨率的DCA曲线的结果文件
R语言使用for循环绘制多个模型的DCA(Decision Curve Analysis)曲线并保存特定分辨率的DCA曲线的结果文件 目录
- 验证曲线( validation curve)是什么?如何绘制验证曲线( validation curve)?验证曲线( validation curve)详解及实践
验证曲线( validation curve)是什么?如何绘制验证曲线( validation curve)?验证曲线( validation curve)详解及实践 验证曲线( validation ...
- ROC曲线是什么?ROC曲线是怎么绘制的?ROC曲线的横纵坐标是什么?如何用Python绘制?AUC又是什么?
ROC曲线是什么?ROC曲线是怎么绘制的?ROC曲线的横纵坐标是什么?AUC又是什么? metrics.roc_auc_score metrics.roc_curve ROC= Receiver Op ...
- canvas贝塞尔曲线爱心_canvas实现高阶贝塞尔曲线(N阶贝塞尔曲线生成器)
写在最前 由于原生的Canvas最高只支持到三阶贝塞尔曲线,那么我想添加多个控制点怎么办呢?(即便大部分复杂曲线都可以用3阶贝塞尔来模拟)与此同时,关于贝塞尔控制点的位置我们很难非常直观的清楚到底将控 ...
- matlibplot 一张图画多个曲线_热重法实验条件设定与曲线解析 第53部分 热重实验方案设计与曲线解析常见问题之热重仪选择中常见问题分析...
在本系列内容第49部分至第52部分中分别介绍了在不同的应用领域中热重曲线解析的常见方法,自本部分内容开始将陆续介绍在热重实验方案设计和曲线解析中的常见问题,在本部分内容中将介绍在热重实验方案设计中选择 ...
- chart控件做实时曲线显示_组态王实时趋势曲线控件介绍,让你对此不再陌生
一.组态王实时趋势控件的特点 1. 通过TCPIP获得实时数据,数据服务器可以是任何一台运行组态王的机器,而不需进行组态王网络配置. 2. 最多可以显示20条曲线. 3. 可以设置每条曲线的绘制方式, ...
最新文章
- AutoCAD LISP花型图案一
- 成长的速度一定要超过父母老去的速度
- matlab中数组创建方法
- Android Studio导入别人的module提示错误Plugin with id ‘com.jfrog.bintray‘ not found.
- ftl 展示图片_视频号变迁的内容展示逻辑
- 关于将表单上传到服务器
- java 单个session过期_session过期的三种方法
- 软件缺陷分析的几种方法
- windows优化大师8周年纪念版_P5SPS4体验版上线|青之驱魔师10周年纪念新卷发售【搞趣日报】...
- 启发式搜索解决八数码难题
- 计算机无法还原,win7系统不能还原如何解决_win7电脑无法还原系统怎么办-win7之家...
- IE6中常见兼容性问题及浏览器显示难题
- 少儿编程强势成2019创业热风口 未来谁才能突围占领C位?
- 无法正常启动0xc0000142的错误
- 培养自己的核心竞争力
- matlab网络通讯消息响应,nevoVI FIRE——实现PC与CAN和LIN网络通信
- 因为一首歌,想念一个人?
- Dojo JQuery
- 深圳大学计算机图形学实验一——OpenGL绘制布布头像
- 分屏多窗开窗画中画多视图播放器
热门文章
- 网页标题上的图片怎么弄呢?
- ttttttttttttt
- form表单中的enctype属性
- 初来乍到,多多关照~~
- 如何用java做游戏地图_Java为游戏绘制地图网格
- 区块链游戏崩盘的前兆有哪些?一文为你分享。
- Linux的httpd
- 全球最大乐高乐园度假区落户深圳;全球最大最高观景摩天轮将开业 | 美通社头条...
- kafka java代码横杠_Apache Beam Kafkaio获取java.lang.illegalargumentException:无法序列化KafkaunBoundedSource...
- python rgba_使用PIL将RGBA PNG转换为RGB