Java分形递归——门格海绵

article/2025/1/6 21:01:32

        门格海绵的结构简单来说就是从一个正方体开始;再把正方体的每一个面分成9个正方形,这时就形成了由27个小正方体组成的一个大正方体;然后再把每一面的中间的正方体和最中心的正方体去掉,最终留下20个正方体。最后,把每一个留下的小正方体都重复前面的步骤。把以上的步骤重复无穷多次以后,得到的图形就是门格海绵。演变过程如下所示:

 在实际代码编程时的思路是将一个门格海绵分为上中下三层,如图:

        如图,将立方体7个顶点依次用p1,p2,p3,p4,p5,p6,p7表示;dx,dy是透视偏移量,立方体的边长设为d。

        基础值设置好后,就可以开始画第一个立方体。绘制思路:通过设置一个立方体顶点的坐标来确定需要的其他六个顶点的坐标,然后画出一个立方体,再将该立方体分为20个小立方体,每个小立方体同样是通过顶点坐标的信息,递归调用画图方法绘制出来的。

         第一步,先画出一个立方体的线框,给三个面填充颜色。

        常规操作,显示一个界面,添加按钮;

package menggehaimian;import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;public class menggehaimian1 extends JFrame {public void initUI(){this.setSize(500,600);this.setTitle("经典分形");this.setDefaultCloseOperation(3);FlowLayout fl = new FlowLayout();this.setLayout(fl);//加上按钮JButton buDraw = new JButton("添加图片");this.add(buDraw);//加监听器this.setVisible(true);//获取画布,一定在界面可见之后Graphics g = this.getGraphics();DrawLisMGHM1 dl = new DrawLisMGHM1(g);buDraw.addActionListener(dl);}public static void main(String[] args) {menggehaimian1 lu=new menggehaimian1();lu.initUI();}
}

在监听器类中实现具体的方法:

package menggehaimian;import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
//画图按钮的监听器,点一下画个东西出来
public class DrawLisMGHM1 implements ActionListener{private Graphics g;public DrawLisMGHM1(Graphics g) {this.g=g;}//画门格海绵//1.画一个线框  2.立体:w h参数@Overridepublic void actionPerformed(ActionEvent arg0) {//根据给定的三组参数,画一个立方体线框:int dx=150,dy=100;int x1=20,y1=200;int d=300;int x2=x1+d,y2=y1;int x3=x2,y3=y2+d;int x4=x1,y4=y1+d;int x5=x1+dx,y5=y1-dy;int x6=x5+d,y6=y5;int x7=x6,y7=y6+d;g.drawLine(x1, y1, x2, y2);g.drawString("p1", x1, y1);g.drawLine(x2, y2, x3, y3);g.drawString("p2", x2, y2);g.drawLine(x3, y3, x4, y4);g.drawString("p3", x3, y3);g.drawLine(x4, y4, x1, y1);g.drawString("p4", x4, y4);g.drawLine(x1, y1, x5, y5);g.drawString("p5", x5, y5);g.drawLine(x5, y5, x6, y6);g.drawString("p6", x6, y6);g.drawLine(x6, y6, x2, y2);g.drawLine(x6, y6, x7, y7);g.drawString("p7", x7, y7);g.drawLine(x7, y7, x3, y3);	//填充面Polygon pon1 = new Polygon();//创建一个多边形用来填充pon1.addPoint(x1, y1);pon1.addPoint(x5, y5);pon1.addPoint(x6, y6);pon1.addPoint(x2, y2);g.setColor(new Color(210,0,0));g.fillPolygon(pon1);Polygon pon2 = new Polygon();//创建一个多边形用来填充pon2.addPoint(x1, y1);pon2.addPoint(x2, y2);pon2.addPoint(x3, y3);pon2.addPoint(x4, y4);g.setColor(new Color(180,0,0));g.fillPolygon(pon2);Polygon pon3 = new Polygon();//创建一个多边形用来填充pon3.addPoint(x2, y2);pon3.addPoint(x6, y6);pon3.addPoint(x7, y7);pon3.addPoint(x3, y3);g.setColor(new Color(100,0,0));g.fillPolygon(pon3);}
}

如图,首先画出第一个正方形;接下来  我们加入递归算法,依次画出其他的立方体。和上面的代码差不多,需要先确定几个固定参数。在这个参数里需要多加一个count参数,控制递归的次数。

public void actionPerformed(ActionEvent e) {//根据给定的三组参数,画一个立方体线框:int x=150,y=200,d=200,dx=100,dy=50,count = 1;//count可以设置递归的次数Menger_Sponge(x, y, d, dx, dy, count);}

其次,通过顶点坐标获取到其他顶点的坐标的方法;在这里,我用p0表示为顶点,表示出其他6个点的坐标。利用条件if(){}else{}语句,表示出下中上三层每个小方块的首地址,并填充颜色。

	private void Menger_Sponge(int x, int y, int d, int dx, int dy, int count) {// 记录单个方块7个顶角的坐标Point p0 = new Point(x, y);Point p1 = new Point(p0.x + d, p0.y);Point p2 = new Point(p1.x, p1.y + d);Point p3 = new Point(p2.x - d, p2.y);Point p4 = new Point(p0.x + dx, p0.y - dy);Point p5 = new Point(p1.x + dx, p1.y - dy);Point p6 = new Point(p2.x + dx, p2.y - dy);count--; //递归次数减1if (count >= 0) {//递归到底层各小方块的首地址Menger_Sponge(p0.x + 2 * dx / 3, p0.y - 2 * dy / 3 + 2 * d / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x + 2 * dx / 3 + d / 3, p0.y - 2 * dy / 3 + 2 * d / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x + 2 * dx / 3 + 2 * d / 3, p0.y - 2 * dy / 3 + 2 * d / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x + dx / 3, p0.y - dy / 3 + 2 * d / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x + dx / 3 + 2 * d / 3, p0.y - dy / 3 + 2 * d / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x, p0.y + 2 * d / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x + d / 3, p0.y + 2 * d / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x + 2 * d / 3, p0.y + 2 * d / 3, d / 3, dx / 3, dy / 3, count);//递归到中层各小方块的首地址Menger_Sponge(p0.x + 2 * dx / 3, p0.y - 2 * dy / 3 + d / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x + 2 * dx / 3 + 2 * d / 3, p0.y - 2 * dy / 3 + d / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x, p0.y + d / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x + 2 * d / 3, p0.y + d / 3, d / 3, dx / 3, dy / 3, count);//递归到顶层各小方块的首地址Menger_Sponge(p0.x + 2 * dx / 3, p0.y - 2 * dy / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x + 2 * dx / 3 + d / 3, p0.y - 2 * dy / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x + 2 * dx / 3 + 2 * d / 3, p0.y - 2 * dy / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x + dx / 3, p0.y - dy / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x + dx / 3 + 2 * d / 3, p0.y - dy / 3, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x, p0.y, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x + d / 3, p0.y, d / 3, dx / 3, dy / 3, count);Menger_Sponge(p0.x + 2 * d / 3, p0.y, d / 3, dx / 3, dy / 3, count);}else {//填充正面矩形Polygon poly1 = new Polygon();poly1.addPoint(p0.x, p0.y);poly1.addPoint(p1.x, p1.y);poly1.addPoint(p2.x, p2.y);poly1.addPoint(p3.x, p3.y);g.setColor(new Color(250, 0, 0));g.fillPolygon(poly1);//填充右面矩形Polygon poly2 = new Polygon();poly2.addPoint(p1.x, p1.y);poly2.addPoint(p2.x, p2.y);poly2.addPoint(p6.x, p6.y);poly2.addPoint(p5.x, p5.y);g.setColor(new Color(180, 0, 0));g.fillPolygon(poly2);//填充上面矩形Polygon poly3 = new Polygon();poly3.addPoint(p0.x, p0.y);poly3.addPoint(p1.x, p1.y);poly3.addPoint(p5.x, p5.y);poly3.addPoint(p4.x, p4.y);g.setColor(new Color(130, 0, 0));g.fillPolygon(poly3);}}
}

        由此就得到了第一个由20个小立方体构成的大立方体。将count的递归次数改为3,就得到了由该立方体递归分形三次后所得的图形,也就是门格海绵。

int x=100,y=200,d=200,dx=100,dy=50,count = 3;

总结:思路并不难,但是因为代码多,坐标定位比较考察数学模型思维,容易忽略某些细节,还有各个代码之间的调试,出现bug找出来也很难,要一步一步,从小细节慢慢找,慢慢检查。以后碰到更复杂的实现过程时,就更要注意。


http://chatgpt.dhexx.cn/article/Ll4ak7iR.shtml

相关文章

门格海绵的实现

实现效果: 源代码: package sponge;import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Polygon;import javax.swing.JFrame;public class Sponge_Main extends JFrame impleme…

混沌与分形(一):谢尔宾斯基三角形与门格海绵

研究混沌运动,少不了对分形理论的探讨。分形:通常被定义为“一个粗糙或零碎的几何形状,可以分成数个部分,且每一部分都(至少近似地)是整体缩小后的形状”,即具有自相似的性质。 本篇将从一维过…

分形之门格海绵

门格海绵解决思路: 1. 迭代如何实现 2. 立方体该怎么画 3. 实现门格海绵代码 4. 画图板门格海绵代码 1. 迭代如何实现 为了实现从1图—>2图—>3图效果,我们就要想到用迭代去实现. 因为像3图这样的图形,是由若干个2图这样的基本图形组成的 那么,怎样实现…

JAVA学习日志之门格海绵

门格海绵的结构可以用以下方法形象化: 从一个正方体开始。(第一个图像) 把正方体的每一个面分成9个正方形。这将把正方体分成27个小正方体,像魔方一样。 把每一面的中间的正方体去掉,把最中心的正方体也去掉&#xff0…

复杂分形,简单规则:门格海绵世界探秘

连绵的山川、飘浮的云朵、岩石的断裂口、布朗粒子运动的轨迹、树冠、花菜、大脑皮层……这些部分与整体以某种方式相似的形体,可以说,就是“分形”的要义了,也恰恰是这些“不规则的”、“分散的”、“支离破碎的”物体又重新让我们认识了自然…

JQData | 高校版使用教程,30秒安装完成,自带Python环境

本地量化金融数据JQData,是聚宽数据团队专门为金融机构、学术团体和量化研究者们提供的本地量化金融数据服务。自有版权,支持国内多家头部券商实盘交易。历经15万量化研究者与数百家机构使用验证。 JQData目前已支持国内30 高校,本次更新&…

JQData + matplotlib 实现回测日志的交易细节可视化 量化数据接口

原文:https://zhuanlan.zhihu.com/p/49051899 前言: 做量化交易的朋友都知道回测的重要性,回测结果是衡量一个量化交易策略是否靠谱的重要依据。回测平台会按历史行情数据模拟成交,并将回测结果汇总成报告。 在很多时候&#xf…

Note: Python学习笔记 -- Anaconda install jqdata

运行代码下列代码,提示错误 没有安装 jqdata。打开Anaconda Prompt 输入 pip install jqdata 提示cannot find command git然后百度了半天,有人说 pip install git 出错可以使用 conda install git 但是依然出错。最后去官网下载了Git:https://git-scm.…

jq使用教程01_最贴心教程,安装JQData全靠这篇指南

Hi, 各位亲爱的小伙伴们! 近来听说有部分小伙伴在安装JQData时遇到了点小麻烦,导致最后没有安装成功,为了帮助小伙伴们快速成功安装JQData,小编今天来为大家排一下“雷”,希望能帮到你们哟 (・ω&#xff6…

事件驱动的选股小工具(JQData)

昨天发改委下发了《关于积极推进风电、光伏发电无补贴平价上网有关工作的通知》,也不知道对股市是利空还是利多。连夜做了一个搜索公司经营范围的小工具,看看那些股票受到影响。 以后还可以增加筛选条件,比如财务指标,剔除ST股票,…

股票python量化交易008-JoinQuant中JQData的使用

查阅JoinQuant中JQData的使用文档python代码实现导入JQData,并认证用户身份。认证完毕显示“auth success”后即可使用 from jqdatasdk import *; auth(ID,Password);#ID是申请时所填写的手机号;Password为聚宽官网登录密码 # 查询jqdata的调用次数情况 surplus_count = g…

jqdata pyechart: 用grid双图实现k线带图成交 — by QUANTAXIS

from jqdatasdk import * from pyecharts import Kline,Bar,Grid 首先我们先应JQDATA 的活动演示一下如何调用pyecharts 画图 auth(acc,password) dataget_price(000001.XSHE) auth success先打印下 data 我们可以看到 jqdata返回的格式是 一个单index的Dataframe data.he…

Quant | JQData使用API简单梳理(二)

聚宽平台实际上提供了两种查询数据的方法,第一种是线上在聚宽平台可以使用的API:jqdata,另外一种则是本地的接口:JQData,是的,你没有看错,只是大小写的不同,搞得一开始我以为完全是同一种。jqdata可以线上通过import jqdata来引入数据接口,本地的JQData则是通过import…

jqdata(data是什么文件格式)

期货交易中bar和tick是什么意思 Bar 的概念 在一定时间段内的时间序列就构成了一根 K 线(日本蜡烛图),单根 K 线被称为 Bar。 如果是一分钟内的 Tick 序列,即构成一根分钟 K 线,又称分钟 Bar; 如果是一天内的分钟序列,即构成一根日…

JQData | 量化界最好用的本地量化金融数据(free free~)

什么是本地量化金融数据 - JQData ? 使用JQData本地量化金融数据服务,可快速查看、计算或接入金融数据信息,解决本地、web、自研金融终端调用数据的需求。支持python多版本及多操作系统。为财经类企业、金融机构、学术研究机构和量化爱好者们…

获取股票数据【使用JQData查询行情数据、财务指标、估值指标】

了解股票: 在上一次量化小科普【什么是量化?常用的股票量化指标、如何搭建量化交易系统】对于量化的概念有了一个基本认识,其中量化的主体在这门课程的学习中是“股票”,而当别人问你:“什么是股票?”&…

JQData安装的问题(本地调用的量化金融数据接口-免费)

JQData简介(1)JQData是聚宽数据团队专门为有志于从事量化投资的金融机构、研究人员以及个人量化爱好者提供的本地量化金融数据。用户只需在本地Python环境下安装JQData数据包,输入三行代码,即可调用由聚宽数据团队专业生产的全套量化金融数据,让你轻松告别平台限制,灵活安…

JQData安装(转)

首先,JQData是基于python的一个数据包,所以安装JQData的第一步是安装Python (没有接触过python或者python基础不好的小伙伴,可以关注聚宽量化课堂的python讲堂进行python学习)。 对于python安装包的选择,…

JQData安装的问题(只解决安装的问题)

1. JQData简介 (1)JQData是聚宽数据团队专门为有志于从事量化投资的金融机构、研究人员以及个人量化爱好者提供的本地量化金融数据。用户只需在本地Python环境下安装JQData数据包,输入三行代码,即可调用由聚宽数据团队专业生产的…

JQData-本地调用的量化金融数据接口(免费)

什么是聚宽数据-JQData? 使用JQData金融数据服务,可快速查看、计算或接入金融数据信息,解决本地、web、自研金融终端调用数据的需求。支持python多版本及多操作系统。为财经类企业、金融机构、学术研究机构和量化爱好者们提供一站式财经信息服务及数据解决方案。 提供哪些…