10. 复数运算可视化

功能简介:支持复数的四则运算、模、幅角计算,通过复平面可视化展示复数及其运算结果。帮助学生理解复数的几何意义和运算规则,适用于复数章节的教学。
在这里插入图片描述
ArkTS代码

@Entry
@Component
struct ComplexCalculator {
  @State private real1: number = 1
  @State private imag1: number = 1
  @State private real2: number = 1
  @State private imag2: number = -1
  @State private operation: string = 'add'
  @State private result: string = ''
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)

  build() {
    Column() {
      Text('🔢 复数运算可视化')
        .fontSize(24).fontWeight(FontWeight.Bold)
        .margin({ bottom: 20 })

      Canvas(this.context)
        .width(400).height(400)
        .backgroundColor('#f5f5f5')
        .onReady(() => this.drawComplex())

      Text('运算选择')
        .fontSize(18).fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 10 })

      Row() {
        Button('加法')
          .width(80)
          .onClick(() => { this.operation = 'add'; this.calculate() })
        Button('减法')
          .width(80)
          .onClick(() => { this.operation = 'subtract'; this.calculate() })
        Button('乘法')
          .width(80)
          .onClick(() => { this.operation = 'multiply'; this.calculate() })
        Button('除法')
          .width(80)
          .onClick(() => { this.operation = 'divide'; this.calculate() })
      }

      Text('复数1: a + bi')
        .fontSize(16).fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 10 })

      Row() {
        Text('实部 a: ')
          .width(70)
        TextInput({
          placeholder: '实部',
          text: this.real1.toString()
        })
          .width(100)
          .onChange((v: string) => {
            this.real1 = parseFloat(v) || 0
            this.calculate()
          })
        Text('虚部 b: ')
          .width(70)
        TextInput({
          placeholder: '虚部',
          text: this.imag1.toString()
        })
          .width(100)
          .onChange((v: string) => {
            this.imag1 = parseFloat(v) || 0
            this.calculate()
          })
      }

      Text('复数2: c + di')
        .fontSize(16).fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 10 })

      Row() {
        Text('实部 c: ')
          .width(70)
        TextInput({
          placeholder: '实部',
          text: this.real2.toString()
        })
          .width(100)
          .onChange((v: string) => {
            this.real2 = parseFloat(v) || 0
            this.calculate()
          })
        Text('虚部 d: ')
          .width(70)
        TextInput({
          placeholder: '虚部',
          text: this.imag2.toString()
        })
          .width(100)
          .onChange((v: string) => {
            this.imag2 = parseFloat(v) || 0
            this.calculate()
          })
      }

      Text('运算结果')
        .fontSize(18).fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 10 })

      Text(this.result)
        .fontSize(16).fontColor('#2196F3')
        .margin({ bottom: 20 })

      Text('复数1信息')
        .fontSize(14).fontColor('#666')
      Text(this.getComplexInfo(this.real1, this.imag1))
        .fontSize(14).fontColor('#666')

      Text('复数2信息')
        .fontSize(14).fontColor('#666')
      Text(this.getComplexInfo(this.real2, this.imag2))
        .fontSize(14).fontColor('#666')
    }
    .padding(20)
  }

  private calculate() {
    let real: number, imag: number

    switch (this.operation) {
      case 'add':
        real = this.real1 + this.real2
        imag = this.imag1 + this.imag2
        break
      case 'subtract':
        real = this.real1 - this.real2
        imag = this.imag1 - this.imag2
        break
      case 'multiply':
        real = this.real1 * this.real2 - this.imag1 * this.imag2
        imag = this.real1 * this.imag2 + this.imag1 * this.real2
        break
      case 'divide':
        const denominator = this.real2 * this.real2 + this.imag2 * this.imag2
        real = (this.real1 * this.real2 + this.imag1 * this.imag2) / denominator
        imag = (this.imag1 * this.real2 - this.real1 * this.imag2) / denominator
        break
      default:
        real = 0
        imag = 0
    }

    const mod = Math.sqrt(real * real + imag * imag)
    const arg = Math.atan2(imag, real) * 180 / Math.PI
    this.result = `结果: ${real.toFixed(2)} + ${imag.toFixed(2)}i, 模: ${mod.toFixed(2)}, 幅角: ${arg.toFixed(2)}°`
    this.drawComplex()
  }

  private drawComplex() {
    const ctx = this.context
    const width = 400
    const height = 400
    const centerX = width / 2
    const centerY = height / 2
    const scale = 50 // 缩放因子
    
    // 清空画布
    ctx.clearRect(0, 0, width, height)
    
    // 绘制坐标轴
    ctx.beginPath()
    ctx.moveTo(50, centerY)
    ctx.lineTo(width - 50, centerY)
    ctx.moveTo(centerX, 50)
    ctx.lineTo(centerX, height - 50)
    ctx.strokeStyle = '#000'
    ctx.lineWidth = 1
    ctx.stroke()
    
    // 绘制网格
    ctx.strokeStyle = '#ddd'
    ctx.lineWidth = 0.5
    for (let i = 1; i < 4; i++) {
      const x = centerX + i * scale
      ctx.beginPath()
      ctx.moveTo(x, 50)
      ctx.lineTo(x, height - 50)
      ctx.stroke()
      
      const x2 = centerX - i * scale
      ctx.beginPath()
      ctx.moveTo(x2, 50)
      ctx.lineTo(x2, height - 50)
      ctx.stroke()
      
      const y = centerY + i * scale
      ctx.beginPath()
      ctx.moveTo(50, y)
      ctx.lineTo(width - 50, y)
      ctx.stroke()
      
      const y2 = centerY - i * scale
      ctx.beginPath()
      ctx.moveTo(50, y2)
      ctx.lineTo(width - 50, y2)
      ctx.stroke()
    }
    
    // 计算运算结果
    let resultReal: number, resultImag: number
    switch (this.operation) {
      case 'add':
        resultReal = this.real1 + this.real2
        resultImag = this.imag1 + this.imag2
        break
      case 'subtract':
        resultReal = this.real1 - this.real2
        resultImag = this.imag1 - this.imag2
        break
      case 'multiply':
        resultReal = this.real1 * this.real2 - this.imag1 * this.imag2
        resultImag = this.real1 * this.imag2 + this.imag1 * this.real2
        break
      case 'divide':
        const denominator = this.real2 * this.real2 + this.imag2 * this.imag2
        resultReal = (this.real1 * this.real2 + this.imag1 * this.imag2) / denominator
        resultImag = (this.imag1 * this.real2 - this.real1 * this.imag2) / denominator
        break
      default:
        resultReal = 0
        resultImag = 0
    }
    
    // 绘制复数1
    const x1 = centerX + this.real1 * scale
    const y1 = centerY - this.imag1 * scale
    ctx.beginPath()
    ctx.arc(x1, y1, 6, 0, 2 * Math.PI)
    ctx.fillStyle = '#2196F3'
    ctx.fill()
    ctx.strokeStyle = '#000'
    ctx.stroke()
    
    // 绘制复数1的向量
    ctx.beginPath()
    ctx.moveTo(centerX, centerY)
    ctx.lineTo(x1, y1)
    ctx.strokeStyle = '#2196F3'
    ctx.lineWidth = 2
    ctx.stroke()
    
    // 绘制复数2
    const x2 = centerX + this.real2 * scale
    const y2 = centerY - this.imag2 * scale
    ctx.beginPath()
    ctx.arc(x2, y2, 6, 0, 2 * Math.PI)
    ctx.fillStyle = '#4CAF50'
    ctx.fill()
    ctx.strokeStyle = '#000'
    ctx.stroke()
    
    // 绘制复数2的向量
    ctx.beginPath()
    ctx.moveTo(centerX, centerY)
    ctx.lineTo(x2, y2)
    ctx.strokeStyle = '#4CAF50'
    ctx.lineWidth = 2
    ctx.stroke()
    
    // 绘制结果复数
    const x3 = centerX + resultReal * scale
    const y3 = centerY - resultImag * scale
    ctx.beginPath()
    ctx.arc(x3, y3, 6, 0, 2 * Math.PI)
    ctx.fillStyle = '#FF5722'
    ctx.fill()
    ctx.strokeStyle = '#000'
    ctx.stroke()
    
    // 绘制结果复数的向量
    ctx.beginPath()
    ctx.moveTo(centerX, centerY)
    ctx.lineTo(x3, y3)
    ctx.strokeStyle = '#FF5722'
    ctx.lineWidth = 2
    ctx.stroke()
    
    // 绘制图例
    ctx.font = '12px Arial'
    ctx.fillStyle = '#000'
    ctx.fillText('复数1', 30, 30)
    ctx.fillText('复数2', 100, 30)
    ctx.fillText('结果', 170, 30)
    
    ctx.fillStyle = '#2196F3'
    ctx.fillRect(25, 15, 10, 10)
    ctx.fillStyle = '#4CAF50'
    ctx.fillRect(95, 15, 10, 10)
    ctx.fillStyle = '#FF5722'
    ctx.fillRect(165, 15, 10, 10)
  }

  private getComplexInfo(real: number, imag: number): string {
    const mod = Math.sqrt(real * real + imag * imag)
    const arg = Math.atan2(imag, real) * 180 / Math.PI
    return `模: ${mod.toFixed(2)}, 幅角: ${arg.toFixed(2)}°`
  }
}
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐