1. 圆周角定理
  • 功能:拖动圆周上的点,观察圆周角大小变化,验证同弧所对圆周角是圆心角的一半。
    核心功能:
    拖动圆周上的点A、B、C,观察角度变化
    实时计算圆心角∠AOB和圆周角∠ACB
    验证圆周角定理:同弧所对圆周角是圆心角的一半
    显示圆周角与圆心角的比值
    在这里插入图片描述
// 点数据接口
interface CircumferentialPoint {
  x: number
  y: number
}

@Entry
@Component
struct CircumferentialAngleTheorem {
  @State centerX: number = 250
  @State centerY: number = 150
  @State radius: number = 100
  @State pointA: CircumferentialPoint = { x: 250, y: 50 }
  @State pointB: CircumferentialPoint = { x: 150, y: 150 }
  @State pointC: CircumferentialPoint = { x: 350, y: 150 }
  @State centralAngle: number = 0
  @State circumferentialAngle: number = 0
  @State isDragging: boolean = false
  @State draggingPoint: 'A' | 'B' | 'C' = 'C'

  build() {
    Column({ space: 20 }) {
      Text('圆周角定理演示')
        .fontSize(26)
        .fontWeight(FontWeight.Bold)

      Column() {
        Text('本应用演示圆周角定理:同弧所对的圆周角是圆心角的一半。用户可以拖动圆周上的点C,观察圆周角∠ACB的大小变化,验证它始终等于圆心角∠AOB的一半。通过直观的交互方式,帮助学生理解圆周角定理的核心内容和几何意义。')
          .fontSize(14)
          .fontColor('#666666')
          .textAlign(TextAlign.Center)
          .lineHeight(22)
          .padding({ left: 20, right: 20 })
      }
      .width('100%')
      .backgroundColor('#E3F2FD')
      .borderRadius(10)
      .padding(15)

      Canvas(this.canvasContext)
        .width(500)
        .height(300)
        .backgroundColor('#FFFFFF')
        .border({ width: 2, color: '#333' })
        .borderRadius(10)
        .onReady(() => {
          this.draw()
        })
        .gesture(
          PanGesture()
            .onActionStart((event) => {
              this.isDragging = true
              this.draggingPoint = this.getDraggingPoint(event.fingerList[0].localX, event.fingerList[0].localY)
            })
            .onActionUpdate((event) => {
              if (this.isDragging) {
                this.updatePointPosition(event.fingerList[0].localX, event.fingerList[0].localY)
                this.calculateAngles()
                this.draw()
              }
            })
            .onActionEnd(() => {
              this.isDragging = false
            })
        )

      Column({ space: 10 }) {
        Row({ space: 20 }) {
          Text('圆心角 ∠AOB')
            .fontSize(16)
            .fontWeight(FontWeight.Medium)
          Text(`${this.centralAngle.toFixed(1)}°`)
            .fontSize(16)
            .fontColor('#2196F3')
        }

        Row({ space: 20 }) {
          Text('圆周角 ∠ACB')
            .fontSize(16)
            .fontWeight(FontWeight.Medium)
          Text(`${this.circumferentialAngle.toFixed(1)}°`)
            .fontSize(16)
            .fontColor('#FF9800')
        }

        Row({ space: 20 }) {
          Text('圆周角 / 圆心角')
            .fontSize(16)
            .fontWeight(FontWeight.Medium)
          Text(`${(this.centralAngle > 0 ? (this.circumferentialAngle / this.centralAngle).toFixed(2) : '0.00')}`)
            .fontSize(16)
            .fontColor('#4CAF50')
        }

        Row({ space: 20 }) {
          Text('定理验证')
            .fontSize(18)
            .fontWeight(FontWeight.Bold)
          Text(this.getTheoremVerification())
            .fontSize(18)
            .fontWeight(FontWeight.Bold)
            .fontColor(this.getVerificationColor())
        }
      }
      .width('90%')
      .padding(20)
      .backgroundColor('#F5F5F5')
      .borderRadius(10)

      Row({ space: 20 }) {
        Button('重置位置')
          .width('30%')
          .height(50)
          .fontSize(18)
          .backgroundColor('#2196F3')
          .onClick(() => {
            this.resetPosition()
          })

        Button('随机位置')
          .width('30%')
          .height(50)
          .fontSize(18)
          .backgroundColor('#4CAF50')
          .onClick(() => {
            this.randomPosition()
          })
      }
      .width('90%')
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Start)
  }

  private canvasContext: CanvasRenderingContext2D = new CanvasRenderingContext2D()

  private getDraggingPoint(x: number, y: number): 'A' | 'B' | 'C' {
    const distanceA = Math.sqrt((x - this.pointA.x) ** 2 + (y - this.pointA.y) ** 2)
    const distanceB = Math.sqrt((x - this.pointB.x) ** 2 + (y - this.pointB.y) ** 2)
    const distanceC = Math.sqrt((x - this.pointC.x) ** 2 + (y - this.pointC.y) ** 2)
    
    const minDistance = Math.min(distanceA, distanceB, distanceC)
    
    if (minDistance < 10) {
      if (minDistance === distanceA) return 'A'
      if (minDistance === distanceB) return 'B'
      return 'C'
    }
    return 'C'
  }

  private updatePointPosition(x: number, y: number) {
    const dx = x - this.centerX
    const dy = y - this.centerY
    const distance = Math.sqrt(dx * dx + dy * dy)
    
    if (distance > 0) {
      const normalizedX = this.centerX + (dx / distance) * this.radius
      const normalizedY = this.centerY + (dy / distance) * this.radius
      
      if (this.draggingPoint === 'A') {
        this.pointA = { x: normalizedX, y: normalizedY }
      } else if (this.draggingPoint === 'B') {
        this.pointB = { x: normalizedX, y: normalizedY }
      } else {
        this.pointC = { x: normalizedX, y: normalizedY }
      }
    }
  }

  private calculateAngles() {
    this.centralAngle = this.calculateAngle(this.pointA, this.centerX, this.centerY, this.pointB)
    this.circumferentialAngle = this.calculateAngle(this.pointA, this.pointC.x, this.pointC.y, this.pointB)
  }

  private calculateAngle(p1: CircumferentialPoint, centerX: number, centerY: number, p2: CircumferentialPoint): number {
    const v1x = p1.x - centerX
    const v1y = p1.y - centerY
    const v2x = p2.x - centerX
    const v2y = p2.y - centerY
    
    const dotProduct = v1x * v2x + v1y * v2y
    const magnitude1 = Math.sqrt(v1x * v1x + v1y * v1y)
    const magnitude2 = Math.sqrt(v2x * v2x + v2y * v2y)
    
    if (magnitude1 === 0 || magnitude2 === 0) {
      return 0
    }
    
    let angle = Math.acos(dotProduct / (magnitude1 * magnitude2)) * (180 / Math.PI)
    
    const crossProduct = v1x * v2y - v1y * v2x
    if (crossProduct < 0) {
      angle = 360 - angle
    }
    
    return angle
  }

  private getTheoremVerification(): string {
    if (this.centralAngle < 0.1) {
      return '请拖动点C'
    }
    
    const ratio = this.circumferentialAngle / this.centralAngle
    if (Math.abs(ratio - 0.5) < 0.05) {
      return '定理成立!'
    } else {
      return '验证中...'
    }
  }

  private getVerificationColor(): string {
    if (this.centralAngle < 0.1) {
      return '#666666'
    }
    
    const ratio = this.circumferentialAngle / this.centralAngle
    if (Math.abs(ratio - 0.5) < 0.05) {
      return '#4CAF50'
    } else {
      return '#FF9800'
    }
  }

  private draw() {
    const ctx = this.canvasContext
    ctx.clearRect(0, 0, 500, 300)

    ctx.save()

    ctx.beginPath()
    ctx.arc(this.centerX, this.centerY, this.radius, 0, 2 * Math.PI)
    ctx.fillStyle = '#E3F2FD'
    ctx.fill()
    ctx.strokeStyle = '#2196F3'
    ctx.lineWidth = 2
    ctx.stroke()

    ctx.beginPath()
    ctx.arc(this.centerX, this.centerY, 3, 0, 2 * Math.PI)
    ctx.fillStyle = '#2196F3'
    ctx.fill()

    ctx.beginPath()
    ctx.moveTo(this.pointA.x, this.pointA.y)
    ctx.lineTo(this.centerX, this.centerY)
    ctx.lineTo(this.pointB.x, this.pointB.y)
    ctx.strokeStyle = '#2196F3'
    ctx.lineWidth = 2
    ctx.stroke()

    ctx.beginPath()
    ctx.moveTo(this.pointA.x, this.pointA.y)
    ctx.lineTo(this.pointC.x, this.pointC.y)
    ctx.lineTo(this.pointB.x, this.pointB.y)
    ctx.strokeStyle = '#FF9800'
    ctx.lineWidth = 2
    ctx.stroke()

    ctx.beginPath()
    ctx.arc(this.pointA.x, this.pointA.y, 8, 0, 2 * Math.PI)
    ctx.fillStyle = '#4CAF50'
    ctx.fill()
    ctx.strokeStyle = '#333'
    ctx.lineWidth = 2
    ctx.stroke()

    ctx.beginPath()
    ctx.arc(this.pointB.x, this.pointB.y, 8, 0, 2 * Math.PI)
    ctx.fillStyle = '#4CAF50'
    ctx.fill()
    ctx.strokeStyle = '#333'
    ctx.lineWidth = 2
    ctx.stroke()

    ctx.beginPath()
    ctx.arc(this.pointC.x, this.pointC.y, 8, 0, 2 * Math.PI)
    ctx.fillStyle = '#FF9800'
    ctx.fill()
    ctx.strokeStyle = '#333'
    ctx.lineWidth = 2
    ctx.stroke()

    ctx.font = '16px sans-serif'
    ctx.fillStyle = '#333'
    ctx.fillText('O', this.centerX + 10, this.centerY - 10)
    ctx.fillText('A', this.pointA.x + 10, this.pointA.y - 10)
    ctx.fillText('B', this.pointB.x + 10, this.pointB.y - 10)
    ctx.fillText('C', this.pointC.x + 10, this.pointC.y - 10)

    this.drawArc(this.pointA, this.pointB, '#2196F3', 0.5)
    this.drawArc(this.pointA, this.pointB, '#FF9800', 0.3, this.pointC)

    ctx.restore()
  }

  private drawArc(p1: CircumferentialPoint, p2: CircumferentialPoint, color: string, lineWidth: number, center?: CircumferentialPoint) {
    const ctx = this.canvasContext
    const arcCenter = center || { x: this.centerX, y: this.centerY }
    
    const startAngle = Math.atan2(p1.y - arcCenter.y, p1.x - arcCenter.x)
    const endAngle = Math.atan2(p2.y - arcCenter.y, p2.x - arcCenter.x)
    
    ctx.beginPath()
    ctx.arc(arcCenter.x, arcCenter.y, this.radius * 0.7, startAngle, endAngle, false)
    ctx.strokeStyle = color
    ctx.lineWidth = lineWidth
    ctx.setLineDash([5, 5])
    ctx.stroke()
    ctx.setLineDash([])
  }

  private resetPosition() {
    this.pointA = { x: 250, y: 50 }
    this.pointB = { x: 150, y: 150 }
    this.pointC = { x: 350, y: 150 }
    this.calculateAngles()
    this.draw()
  }

  private randomPosition() {
    const angleA = Math.random() * Math.PI * 2
    const angleB = angleA + Math.random() * Math.PI
    const angleC = angleA + Math.random() * Math.PI * 2
    
    this.pointA = {
      x: this.centerX + Math.cos(angleA) * this.radius,
      y: this.centerY + Math.sin(angleA) * this.radius
    }
    
    this.pointB = {
      x: this.centerX + Math.cos(angleB) * this.radius,
      y: this.centerY + Math.sin(angleB) * this.radius
    }
    
    this.pointC = {
      x: this.centerX + Math.cos(angleC) * this.radius,
      y: this.centerY + Math.sin(angleC) * this.radius
    }
    
    this.calculateAngles()
    this.draw()
  }
}
Logo

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

更多推荐