From dde70ac275082bd4775b3d042df6fe1e731e5f30 Mon Sep 17 00:00:00 2001 From: 13766800364 <13766800364@qq.com> Date: Thu, 9 Oct 2025 16:11:23 +0800 Subject: [PATCH] Add File --- .../drinkjava2/frog/brain/BrainPicture.java | 496 ++++++++++++++++++ 1 file changed, 496 insertions(+) create mode 100644 history/016b_twoinput_unfinish/src/main/java/com/gitee/drinkjava2/frog/brain/BrainPicture.java diff --git a/history/016b_twoinput_unfinish/src/main/java/com/gitee/drinkjava2/frog/brain/BrainPicture.java b/history/016b_twoinput_unfinish/src/main/java/com/gitee/drinkjava2/frog/brain/BrainPicture.java new file mode 100644 index 0000000..1c27f3f --- /dev/null +++ b/history/016b_twoinput_unfinish/src/main/java/com/gitee/drinkjava2/frog/brain/BrainPicture.java @@ -0,0 +1,496 @@ +package com.gitee.drinkjava2.frog.brain; + +import static java.awt.Color.BLACK; +import static java.awt.Color.RED; +import static java.awt.Color.WHITE; +import static java.lang.Math.cos; +import static java.lang.Math.round; +import static java.lang.Math.sin; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.image.BufferedImage; +import java.util.ArrayList; + +import javax.swing.JPanel; + +import com.gitee.drinkjava2.frog.Animal; +import com.gitee.drinkjava2.frog.Application; +import com.gitee.drinkjava2.frog.Env; +import com.gitee.drinkjava2.frog.util.ColorUtils; +import com.gitee.drinkjava2.frog.util.Tree8Util; + +/** + * BrainPicture show first frog's brain structure, for debug purpose only + * + * 这个类用来画出脑图,这不是一个关键类,对脑的运行逻辑无影响,但有了脑图后可以直观地看出脑的3维结构,进行有针对性的改进 + * 可以用鼠标进行平移、缩放、旋转,以及t、f、l、r,x五个键来选择顶视、前视、左视、右视、斜视这5个方向的视图,以及空格暂停、方向键调整切面 + * 鼠标的动作定义在MouseAction类中。 + * + * @author Yong Zhu + * @since 1.0 + */ +@SuppressWarnings("all") +public class BrainPicture extends JPanel { + private static final long serialVersionUID = 1L; + + private static final float D90 = (float) (Math.PI / 2); + + Color picColor = RED; + int brainDispWidth; // screen display piexls width + float scale; // brain scale + int xOffset = 0; // brain display x offset compare to screen + int yOffset = 0; // brain display y offset compare to screen + float xAngle = D90 * .8f; // brain rotate on x axis + float yAngle = D90 / 4; // brain rotate on y axis + float zAngle = 0;// brain rotate on z axis + int xMask = -1;// x Mask + int yMask = -1;// y Mask + BufferedImage buffImg; + Graphics g; + String note; + public KeyAdapter keyAdapter; + + public BrainPicture(int x, int y, float brainWidth, int brainDispWidth) { + super(); + this.setLayout(null);// 空布局 + this.brainDispWidth = brainDispWidth; + scale = 0.5f * brainDispWidth / brainWidth; + this.setBounds(x, y, brainDispWidth + 1, brainDispWidth + 1); + buffImg = new BufferedImage(Env.FROG_BRAIN_DISP_WIDTH, Env.FROG_BRAIN_DISP_WIDTH, BufferedImage.TYPE_INT_RGB); + g = buffImg.getGraphics(); + MouseAction act = new MouseAction(this); + this.addMouseListener(act); // 添加鼠标动作监听 + this.addMouseWheelListener(act);// 添加鼠标滚轮动作监听 + this.addMouseMotionListener(act);// 添加鼠标移动动作监听 + + keyAdapter = new KeyAdapter() {// 处理t,f,l,r,x键盘命令 + @Override + public void keyPressed(KeyEvent e) { + switch (e.getKeyCode()) { + case KeyEvent.VK_UP:// Y切面向上 + yMask++; + if (yMask > Env.BRAIN_SIZE) + yMask = Env.BRAIN_SIZE; + break; + case KeyEvent.VK_DOWN:// Y切面向下 + yMask--; + if (yMask < 0) + yMask = 0; + break; + case KeyEvent.VK_LEFT:// x切面向左 + xMask--; + if (xMask < 0) + xMask = 0; + break; + case KeyEvent.VK_RIGHT:// x切面向右 + xMask++; + if (xMask > Env.BRAIN_SIZE) + xMask = Env.BRAIN_SIZE; + break; + case ' ':// 暂停及继续 + Application.pauseAction.actionPerformed(null); + break; + case 'T':// 顶视 + xAngle = 0; + yAngle = 0; + zAngle = 0; + break; + case 'F':// 前视 + xAngle = D90; + yAngle = 0; + zAngle = 0; + break; + case 'L':// 左视 + xAngle = D90; + yAngle = D90; + zAngle = 0; + break; + case 'R':// 右视 + xAngle = D90; + yAngle = -D90; + zAngle = 0; + break; + case 'X':// 斜视 + xAngle = D90 * .8f; + yAngle = D90 / 4; + zAngle = 0; + break; + default: + } + } + }; + addKeyListener(keyAdapter); + this.setFocusable(true); + } + + public void drawCuboid(float x, float y, float z, float xe, float ye, float ze) {// 在脑图上画一个长立方体框架,视角是TopView + drawLine(x, y, z, x + xe, y, z);// 画立方体的下面边 + drawLine(x + xe, y, z, x + xe, y + ye, z); + drawLine(x + xe, y + ye, z, x, y + ye, z); + drawLine(x, y + ye, z, x, y, z); + + drawLine(x, y, z, x, y, z + ze);// 画立方体的中间边 + drawLine(x + xe, y, z, x + xe, y, z + ze); + drawLine(x + xe, y + ye, z, x + xe, y + ye, z + ze); + drawLine(x, y + ye, z, x, y + ye, z + ze); + + drawLine(x, y, z + ze, x + xe, y, z + ze);// 画立方体的上面边 + drawLine(x + xe, y, z + ze, x + xe, y + ye, z + ze); + drawLine(x + xe, y + ye, z + ze, x, y + ye, z + ze); + drawLine(x, y + ye, z + ze, x, y, z + ze); + } + + public void drawCentLine(float px1, float py1, float pz1, float px2, float py2, float pz2) {// 从细胞中点之间画一条线 + drawLine(px1 + 0.5f, py1 + 0.5f, pz1 + 0.5f, px2 + 0.5f, py2 + 0.5f, pz2 + 0.5f); + } + + /*- + 画线,固定以top视角的角度,所以只需要从x1,y1画一条到x2,y2的直线 + 绕 x 轴旋转 θ + x, y.cosθ-zsinθ, y.sinθ+z.cosθ + + 绕 y 轴旋转 θ + z.sinθ+x.cosθ, y, z.cosθ-x.sinθ + + 绕 z 轴旋转 θ + x.cosθ-y.sinθ, x.sinθ+y.consθ, z + -*/ + public void drawLine(float px1, float py1, float pz1, float px2, float py2, float pz2) { + double x1 = px1 - Env.BRAIN_SIZE / 2; + double y1 = -py1 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来 + double z1 = pz1 - Env.BRAIN_SIZE / 2; + double x2 = px2 - Env.BRAIN_SIZE / 2; + double y2 = -py2 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来 + double z2 = pz2 - Env.BRAIN_SIZE / 2; + x1 = x1 * scale; + y1 = y1 * scale; + z1 = z1 * scale; + x2 = x2 * scale; + y2 = y2 * scale; + z2 = z2 * scale; + double x, y, z; + y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转 + z = y1 * sin(xAngle) + z1 * cos(xAngle); + y1 = y; + z1 = z; + + x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转 + // z = z1 * cos(yAngle) - x1 * sin(yAngle); + x1 = x; + // z1 = z; + + x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转 + y = x1 * sin(zAngle) + y1 * cos(zAngle); + x1 = x; + y1 = y; + + y = y2 * cos(xAngle) - z2 * sin(xAngle);// 绕x轴转 + z = y2 * sin(xAngle) + z2 * cos(xAngle); + y2 = y; + z2 = z; + + x = z2 * sin(yAngle) + x2 * cos(yAngle);// 绕y轴转 + // z = z2 * cos(yAngle) - x2 * sin(yAngle); + x2 = x; + // z2 = z; + + x = x2 * cos(zAngle) - y2 * sin(zAngle);// 绕z轴转 + y = x2 * sin(zAngle) + y2 * cos(zAngle); + x2 = x; + y2 = y; + + g.setColor(picColor); + g.drawLine((int) round(x1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset, + (int) round(y1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset, + (int) round(x2) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset, + (int) round(y2) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset); + } + + public void drawPointCent(float px1, float py1, float pz1, float r) { + drawPoint(px1+0.5f, py1+0.5f, pz1+0.5f, r); + } + + /** 画点,固定以top视角的角度,所以只需要在x1,y1位置画一个点 */ + public void drawPoint(float px1, float py1, float pz1, float r) { + double x1 = px1 - Env.BRAIN_SIZE / 2; + double y1 = -py1 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来 + double z1 = pz1 - Env.BRAIN_SIZE / 2; + x1 = x1 * scale; + y1 = y1 * scale; + z1 = z1 * scale; + double x, y, z; + y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转 + z = y1 * sin(xAngle) + z1 * cos(xAngle); + y1 = y; + z1 = z; + + x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转 + // z = z1 * cos(yAngle) - x1 * sin(yAngle); + x1 = x; + // z1 = z; + + x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转 + y = x1 * sin(zAngle) + y1 * cos(zAngle); + x1 = x; + y1 = y; + + g.setColor(picColor); + g.fillOval(round((float) x1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset - r * scale * .5f), + round((float) y1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset - r * scale * .5f), round(r * scale), + round(r * scale)); + } + + /** 画一个圆 */ + public void drawCircle(float px1, float py1, float pz1, float r) {// 这个方法实际和上面的一样的,只是改成了drawOval + double x1 = px1 - Env.BRAIN_SIZE / 2; + double y1 = -py1 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来 + double z1 = pz1 - Env.BRAIN_SIZE / 2; + x1 = x1 * scale; + y1 = y1 * scale; + z1 = z1 * scale; + double x, y, z; + y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转 + z = y1 * sin(xAngle) + z1 * cos(xAngle); + y1 = y; + z1 = z; + + x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转 + // z = z1 * cos(yAngle) - x1 * sin(yAngle); + x1 = x; + // z1 = z; + + x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转 + y = x1 * sin(zAngle) + y1 * cos(zAngle); + x1 = x; + y1 = y; + + g.setColor(picColor); + g.drawOval(round((float) x1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset - r * scale * .5f), + round((float) y1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset - r * scale * .5f), round(r * scale), + round(r * scale)); + } + + public void drawTextCenter(float px1, float py1, float pz1, String text, float textSize) { + drawText(px1 + 0.5f, py1 + 0.5f, pz1 + 0.5f, text, textSize); + } + + public void drawText(float px1, float py1, float pz1, String text, float textSize) { + double x1 = px1 - Env.BRAIN_SIZE / 2; + double y1 = -py1 + Env.BRAIN_SIZE / 2;// 屏幕的y坐标是反的,显示时要正过来 + double z1 = pz1 - Env.BRAIN_SIZE / 2; + x1 = x1 * scale; + y1 = y1 * scale; + z1 = z1 * scale; + double x, y, z; + y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转 + z = y1 * sin(xAngle) + z1 * cos(xAngle); + y1 = y; + z1 = z; + + x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转 + // z = z1 * cos(yAngle) - x1 * sin(yAngle); + x1 = x; + // z1 = z; + + x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转 + y = x1 * sin(zAngle) + y1 * cos(zAngle); + x1 = x; + y1 = y; + + g.setColor(picColor); + g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, (int) round(textSize * scale))); + g.drawString(text, (int) round(x1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset, + (int) round(y1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset); + + } + + public void drawBrainPicture(int step) {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类,所以也可以当参数传进来 + if (!Env.SHOW_FIRST_ANIMAL_BRAIN) + return; + if (Env.show_split_detail) + drawSplitDetail(); + else + drawBrainStructure(step); + } + + public void drawSplitDetail() {// 在这个方法里绘制脑细胞分裂的显示步聚,即从一个细胞开始分裂成最终脑结构的每一步 + Animal a = Env.getShowAnimal(); // 第一个青蛙或蛇 + + for (int i = Env.BRAIN_SIZE; i >= 1; i /= 2) { + g.setColor(WHITE);// 先清空旧图, g是buffImg,绘在内存中 + g.fillRect(0, 0, brainDispWidth, brainDispWidth); + g.setColor(BLACK); // 画边框 + g.drawRect(0, 0, brainDispWidth, brainDispWidth); + + for (int geneIndex = 0; geneIndex < Genes.GENE_NUMBERS; geneIndex++) { + ArrayList gene = a.genes.get(geneIndex); + Tree8Util.knockNodesByGene(gene); + for (int j = 0; j < Tree8Util.NODE_QTY; j++) { + if (Tree8Util.keep[j] > 0) { + int[] node = Tree8Util.TREE8[j]; + int size = node[0]; + if (size == i && Genes.display_gene[geneIndex]) {// 如果允许显示的话, 显示当前层级的节点 + setPicColor(ColorUtils.colorByCode(geneIndex)); + drawPoint(node[1] + size / 2, node[2] + size / 2, node[3] + size / 2, + size * (0.5f - geneIndex * 0.05f)); + } + } + } + } + g.setColor(BLACK); + drawCuboid(0, 0, 0, Env.BRAIN_SIZE, Env.BRAIN_SIZE, Env.BRAIN_SIZE);// 把脑的框架画出来 + this.getGraphics().drawImage(buffImg, 0, 0, this);// 利用缓存避免画面闪烁,这里输出缓存图片 + if (!Env.show_split_detail) + return; + try { + Thread.sleep(500); + } catch (InterruptedException e) { + } + } + } + + public void drawBrainStructure(int step) {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类,所以也可以当参数传进来 + Animal a = Env.getShowAnimal(); // 显示第一个青蛙或蛇 + if (a == null || !a.alive) + return; + g.setColor(WHITE);// 先清空旧图, g是buffImg,绘在内存中 + g.fillRect(0, 0, brainDispWidth, brainDispWidth); + g.setColor(BLACK); // 画边框 + g.drawRect(0, 0, brainDispWidth, brainDispWidth); + + for (int z = 0; z < Env.BRAIN_SIZE; z++) {// 画它所有的脑细胞位置和颜色 + for (int y = Env.BRAIN_SIZE - 1; y >= 0; y--) { + for (int x = Env.BRAIN_SIZE - 1; x >= 0; x--) { + setPicColor(BLACK); // 画边框 + drawPointCent(x, y, z, 0.03f); //画每个细胞小点 + + long cell = a.cells[x][y][z]; + // if (cell == 0) //只显示有效的细胞点 + // continue; + + if (x >= xMask && y >= yMask && cell != 0)// 画出细胞每个基因存在的细胞格子 + for (int geneIndex = 0; geneIndex < Genes.GENE_NUMBERS; geneIndex++) { + if ((cell & (1 << geneIndex)) != 0 && Genes.display_gene[geneIndex]) { + setPicColor(ColorUtils.colorByCode(geneIndex)); // 开始画出对应的细胞基因参数,用不同颜色圆表示 + drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, 0.3f); + } + } + float e = a.energys[x][y][z]; + if (e > 0.03f || e < -0.03f) { + setPicColor(e > 0 ? Color.red : Color.BLUE); // 用红色小圆表示正能量,蓝色表示负能量 + float size = Math.abs(e);// 再用不同大小圆形表示不同能量值 + if (size > 1) + size = 1; + drawCircle(x + 0.5f, y + 0.5f, z + 0.5f, size); + } + + } + } + } + + setPicColor(Color.BLACK); //画出 a.lines里所有线条 + Line.drawOnBrainPicture(a, this); + + for (Object[] o : Genes.dots) { // 画出所有登记的点的名字 + String name = (String) o[0]; + int x = (int) o[1]; + int y = (int) o[2]; + int z = (int) o[3]; + drawTextCenter(x, y, z, name, 0.3f); + } + + drawCuboid(0, 0, 0, Env.BRAIN_SIZE, Env.BRAIN_SIZE, Env.BRAIN_SIZE);// 把脑的框架画出来 + + setPicColor(BLACK); // 把x,y,z坐标画出来 + drawText(Env.BRAIN_SIZE, 0, 0, "x", Env.BRAIN_SIZE * 0.2f); + drawText(0, Env.BRAIN_SIZE, 0, "y", Env.BRAIN_SIZE * 0.2f); + drawText(0, 0, Env.BRAIN_SIZE, "z", Env.BRAIN_SIZE * 0.2f); + setPicColor(RED); + drawLine(0, 0, 0, Env.BRAIN_SIZE, 0, 0); + drawLine(0, 0, 0, 0, Env.BRAIN_SIZE, 0); + drawLine(0, 0, 0, 0, 0, Env.BRAIN_SIZE); + + g.setColor(Color.black); + if (note != null) {// 全局注释 + g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16)); + g.drawString(note, 10, 20); + } + + g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16)); + g.drawString("step:" + step + ", ate:" + a.ateFood + ", wrong:" + a.ateWrong+", miss:" + a.ateMiss+", fat="+a.fat, 10, 15); + + // for (int y = 0; y < ColorUtils.rainbow.length; y += 1) {//调试彩虹色 + // g.setColor(ColorUtils.rainbow[y]); + // for (int i = 0; i < 9; i++) + // g.drawLine(0, y * 9 + i, 50, y * 9 + i); + // } + + this.getGraphics().drawImage(buffImg, 0, 0, this);// 利用缓存避免画面闪烁,这里输出缓存图片 + } + + public static void setNote(String note) { + Application.brainPic.note = note; + } + + // getters & setters + public float getScale() { + return scale; + } + + public void setScale(float scale) { + this.scale = scale; + } + + public float getxAngle() { + return xAngle; + } + + public void setxAngle(float xAngle) { + this.xAngle = xAngle; + } + + public float getyAngle() { + return yAngle; + } + + public void setyAngle(float yAngle) { + this.yAngle = yAngle; + } + + public float getzAngle() { + return zAngle; + } + + public void setzAngle(float zAngle) { + this.zAngle = zAngle; + } + + public void setPicColor(Color color) { + this.picColor = color; + } + + public Color getPicColor() { + return picColor; + } + + public int getxOffset() { + return xOffset; + } + + public void setxOffset(int xOffset) { + this.xOffset = xOffset; + } + + public int getyOffset() { + return yOffset; + } + + public void setyOffset(int yOffset) { + this.yOffset = yOffset; + } + +}