自制分形查看器 i^4 - 1 = 0

自制分形查看器 i^4 - 1 = 0

  • 一、效果演示
  • 二、代码实现
      • 1.先实现复数类
      • 2.再根据数值绘制不同的颜色
      • 3.最后绘制
  • 三、有个问题

具体实现 代码软件加QQ群 : 302493982 获取

一、效果演示

可以鼠标拖动查看

自制分形查看器 i^4 - 1 = 0_第1张图片
自制分形查看器 i^4 - 1 = 0_第2张图片

滚轮可以放大某一块

自制分形查看器 i^4 - 1 = 0_第3张图片

右下角显示当前鼠标的位置

左下角显示当前屏幕显示的位置,由于是复平面,所以横轴是石洲,纵轴是虚轴
在这里插入图片描述

左上角菜单可以改变清晰度,1会很卡,可能每一帧要运行半分钟,看电脑配置

自制分形查看器 i^4 - 1 = 0_第4张图片

自制分形查看器 i^4 - 1 = 0_第5张图片
自制分形查看器 i^4 - 1 = 0_第6张图片

二、代码实现

具体实现代码软件加QQ群 : 302493982 获取

本demo是用scala写的 因为可以重载操作运算符,Qt/c++有点麻烦就没用

1.先实现复数类

package rsslosc.x_4__1.scala

class Complex(val a: Double, val b: Double) {
     
  def getA: Double = a
  def getB: Double = b

  def +(complex: Complex): Complex = {
     
    val c = complex.getA
    val d = complex.getB
    new Complex(a + c, b + d)
  }

  def -(complex: Complex): Complex = {
     
    val c = complex.getA
    val d = complex.getB
    new Complex(a - c, b - d)
  }

  def *(complex: Complex): Complex = {
     
    val c = complex.getA
    val d = complex.getB
    new Complex(a * c - b * d, b * c + a * d)
  }

  def /(complex: Complex): Complex = {
     
    val c = complex.getA
    val d = complex.getB
    new Complex((a * c + b * d) / (c * c + d * d), (b * c - a * d) / (c * c + d * d))
  }

  def ^(n: Long): Complex = {
     
    if (n < 1) {
     
      return new Complex(0, 0)
    }
    var n_ = n
    var that = this
    var ans = new Complex(1, 0)
    while (n_ > 0) {
     
      if ((n_ & 1) == 1) {
     
        ans = ans * that
      }
      n_ >>= 1
      that = that * that
    }
    ans
  }

  def distance(complex: Complex): Double = {
     
    val c = complex.getA
    val d = complex.getB
    Math.sqrt(Math.pow(a - c, 2) + Math.pow(b - d, 2))
  }

  override def toString: String = {
     
    if (b > 0) return a + " + " + b + " i"
    else if (b < 0) return a + " - " + -b + " i"
    a + ""
  }
}

object Complex {
     
  def apply(a: Double, b: Double): Complex = new Complex(a, b)
}

2.再根据数值绘制不同的颜色

package rsslosc.x_4__1.scala

class ChooseColor {
     
  def color(p: Complex): String = {
     
    var point: Complex = p
    var min: Double = 0x3f3f3f3f
    var d_1: Double = 0
    var d__1: Double = 0
    var d_i: Double = 0
    var d__i: Double = 0
    var mark = 0
    while (min > 1e-2 && mark < 30) {
     
      val fenzi = (point ^ 4) - Complex(1, 0)
      val fenmu = (point ^ 3) * Complex(4, 0)
      point = point - (fenzi / fenmu)
      d_1 = point distance Complex(1, 0)
      d__1 = point distance Complex(-1, 0)
      d_i = point distance Complex(0, 1)
      d__i = point distance Complex(0, -1)
      min = Math.min(d_1, Math.min(d__1, Math.min(d_i, d__i)))
      mark += 1
    }
    if (d_1 - min < 1e-2) return "1"
    if (d__1 - min < 1e-2) return "-1"
    if (d_i - min < 1e-2) return "i"
    "-i"
  }
}

3.最后绘制

package rsslosc.x_4__1.scala


import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.control.{
     Label, Menu, MenuBar, MenuItem}
import javafx.scene.input.MouseEvent
import javafx.scene.layout._
import javafx.scene.paint.Color
import javafx.scene.shape.Rectangle
import javafx.stage.Stage

object Draw {
     
  def main(args: Array[String]): Unit = {
     
    Application.launch(classOf[Draw], args: _*)
  }
}

class Draw extends Application {
     
  val X: Int = 1000 //画布长度
  val Y: Int = 700 //画布宽度

  var grainSize: Int = 5 //精度  数值越大,精度越小

  var init_x: Double = -150 //初始x坐标
  var init_y: Double = -100 //初始y坐标

  var rangeAccuracy_a: Int = 3 //缩放比例分子
  var rangeAccuracy_b: Int = 10 //缩放比例分母

  override def start(primaryStage: Stage): Unit = {
     
    val vBox: VBox = new VBox
    val hBox: HBox = new HBox
    val labelLeft: Label = new Label
    val pane: Pane = new Pane
    HBox.setHgrow(pane, Priority.ALWAYS)
    val labelRight: Label = new Label

    hBox.getChildren.addAll(labelLeft, pane, labelRight)
    val anchorPane: AnchorPane = new AnchorPane

    val menuBar: MenuBar = new MenuBar
    val menuChange: Menu = new Menu("_Change")
    val menuChangeGrainSize: Menu = new Menu("change grain size")
    val menuItemChangeGrainSize_1: MenuItem = new MenuItem("1")
    val menuItemChangeGrainSize_2: MenuItem = new MenuItem("2")
    val menuItemChangeGrainSize_3: MenuItem = new MenuItem("3")
    val menuItemChangeGrainSize_4: MenuItem = new MenuItem("4")


    menuChangeGrainSize.getItems.addAll(menuItemChangeGrainSize_1, menuItemChangeGrainSize_2,
      menuItemChangeGrainSize_3, menuItemChangeGrainSize_4)
    menuItemChangeGrainSize_1.setOnAction(_ => {
     
      grainSize = 1
      anchorPane.getChildren.remove(0 , anchorPane.getChildren.size())
      anchorPane.getChildren.addAll(drawImg(): _*)
    })
    menuItemChangeGrainSize_2.setOnAction(_ => {
     
      grainSize = 2
      anchorPane.getChildren.remove(0 , anchorPane.getChildren.size())
      anchorPane.getChildren.addAll(drawImg(): _*)
    })
    menuItemChangeGrainSize_3.setOnAction(_ => {
     
      grainSize = 3
      anchorPane.getChildren.remove(0 , anchorPane.getChildren.size())
      anchorPane.getChildren.addAll(drawImg(): _*)
    })
    menuItemChangeGrainSize_4.setOnAction(_ => {
     
      grainSize = 4
      anchorPane.getChildren.remove(0 , anchorPane.getChildren.size())
      anchorPane.getChildren.addAll(drawImg(): _*)
    })

    menuChange.getItems.add(menuChangeGrainSize)
    menuBar.getMenus.add(menuChange)



    var moveBeginX: Double = 0
    var moveBeginY: Double = 0

    anchorPane.setOnScroll(e => {
     
      val oldRangeAccuracy = rangeAccuracy_a.doubleValue() / rangeAccuracy_b.doubleValue()
      if (e.getTextDeltaY > 0) rangeAccuracy_a -= 1 else rangeAccuracy_a += 1
      if (rangeAccuracy_a == 0) {
     
        rangeAccuracy_a = 9
        rangeAccuracy_b *= 10
      }
      if (rangeAccuracy_a == 10) {
     
        rangeAccuracy_a = 1
        rangeAccuracy_b /= 10
      }
      val newRangeAccuracy = rangeAccuracy_a.doubleValue() / rangeAccuracy_b.doubleValue()
      val changeAccuracy = oldRangeAccuracy - newRangeAccuracy
      init_x += changeAccuracy * e.getX
      init_y += changeAccuracy * e.getY

      anchorPane.getChildren.clear()
      anchorPane.getChildren.addAll(drawImg(): _*)
      writeLabel(labelLeft)
    })

    anchorPane.setOnMouseMoved(e => {
     
      writeNowLocation(labelRight,e)
    })

    anchorPane.setOnMouseExited(_ => {
     
      labelRight.setText("")
    })

    anchorPane.setOnMousePressed(e => {
     
      moveBeginX = e.getX
      moveBeginY = e.getY
    })

    anchorPane.setOnMouseReleased(e => {
     
      init_x -= (e.getX - moveBeginX) * (rangeAccuracy_a.doubleValue() / rangeAccuracy_b.doubleValue())
      init_y -= (e.getY - moveBeginY) * (rangeAccuracy_a.doubleValue() / rangeAccuracy_b.doubleValue())
      anchorPane.getChildren.clear()
      anchorPane.getChildren.addAll(drawImg(): _*)
      writeLabel(labelLeft)
    })

    writeLabel(labelLeft)
    anchorPane.getChildren.addAll(drawImg(): _*)
    vBox.getChildren.addAll(menuBar, anchorPane, hBox)
    primaryStage.setScene(new Scene(vBox, X, Y + 50))
    primaryStage.show()
  }

  def writeNowLocation(label: Label, e: MouseEvent): Unit = {
     
    val nowAccuracy = rangeAccuracy_a.doubleValue() / rangeAccuracy_b.doubleValue()
    label.setText("当前位置: " + (init_x + e.getX * nowAccuracy).formatted("%.4f") +
      " + " + (-init_y - e.getY * nowAccuracy).formatted("%.4f") + " i ")
  }

  def writeLabel(label: Label): Unit = {
     
    val nowAccuracy = rangeAccuracy_a.doubleValue() / rangeAccuracy_b.doubleValue()
    label.setText("实轴 : " + init_x.formatted("%.4f") + " ~ " + (init_x + nowAccuracy * X).formatted("%.4f") +
      "   虚轴 : " + (-init_y - nowAccuracy * Y).formatted("%.4f") + " i ~ " + (-init_y).formatted("%.4f") + " i")
  }

  def drawImg(): Array[Rectangle] = {
     
    val chooseColor: ChooseColor = new ChooseColor
    val rectangle: Array[Rectangle] = new Array[Rectangle]((X / grainSize) * (Y / grainSize))

    var index: Int = 0

    val rangeAccuracy: Double = rangeAccuracy_a.doubleValue() / rangeAccuracy_b.doubleValue()

    for (i <- 0 until X / grainSize) {
     
      for (j <- 0 until Y / grainSize) {
     
        rectangle(index) = new Rectangle(i * grainSize, j * grainSize, grainSize, grainSize)
        chooseColor.color(
          new Complex(init_x + rangeAccuracy * i * grainSize, init_y + rangeAccuracy * j * grainSize)
        ) match {
     
          case "1" => rectangle(index).setFill(Color.RED)
          case "-1" => rectangle(index).setFill(Color.BLUE)
          case "i" => rectangle(index).setFill(Color.GREEN)
          case "-i" => rectangle(index).setFill(Color.ORANGE)
        }
        index += 1
      }
    }
    rectangle
  }
}

三、有个问题

有个问题 : 改变清晰度内存不减,有大佬来帮忙看看
System.gc() 没用
anchorPane.getChildren.clear() 没用

你可能感兴趣的:(math,极致通俗,完整项目,windows,java,抽象代数,拓扑学)