1. 分形几何之科赫雪花
    • 功能:迭代绘制科赫雪花,展示有限面积、无限周长的数学悖论。
      科赫雪花应用通过迭代绘制科赫雪花,展示有限面积、无限周长的数学悖论。科赫雪花是由瑞典数学家海里格·冯·科赫于1904年提出的一种分形曲线,具有惊人的特性:在有限的空间内可以拥有无限长的周长,这是分形几何中最著名的例子之一。本应用通过可视化方式展示科赫雪花的生成过程,帮助用户理解这一神奇的数学现象。
      在这里插入图片描述
// 分形几何之科赫雪花
// 功能:迭代绘制科赫雪花,展示有限面积、无限周长的数学悖论。
// 科赫雪花是由瑞典数学家海里格·冯·科赫于1904年提出的一种分形曲线。
// 它具有惊人的特性:在有限的空间内可以拥有无限长的周长,这是分形几何中最著名的例子之一。
// 本应用通过可视化方式展示科赫雪花的生成过程,帮助用户理解这一神奇的数学现象。

// 点接口
interface KochPoint {
  x: number;
  y: number;
}

// 线段接口
interface LineSegment {
  start: KochPoint;
  end: KochPoint;
}

@Entry
@Component
struct KochSnowflake {
  @State iteration: number = 3;
  @State maxIteration: number = 6;
  @State isAnimating: boolean = false;
  @State animationProgress: number = 0;
  @State showConstruction: boolean = false;
  @State canvasWidth: number = 350;
  @State canvasHeight: number = 350;
  @State snowflakeColor: string = '#2196F3';
  @State lineWidth: number = 1.5;

  private canvasContext: CanvasRenderingContext2D = new CanvasRenderingContext2D();
  private colors: string[] = ['#E91E63', '#2196F3', '#4CAF50', '#FF9800', '#9C27B0', '#00BCD4'];

  private calculateKochPoints(start: KochPoint, end: KochPoint, iteration: number): KochPoint[] {
    if (iteration === 0) {
      return [start, end];
    }

    const dx = end.x - start.x;
    const dy = end.y - start.y;

    const p1: KochPoint = {
      x: start.x + dx / 3,
      y: start.y + dy / 3
    };

    const p2: KochPoint = {
      x: start.x + 2 * dx / 3,
      y: start.y + 2 * dy / 3
    };

    const midX = (start.x + end.x) / 2;
    const midY = (start.y + end.y) / 2;

    const height = Math.sqrt(3) / 6 * Math.sqrt(dx * dx + dy * dy);

    const perpX = -dy / Math.sqrt(dx * dx + dy * dy);
    const perpY = dx / Math.sqrt(dx * dx + dy * dy);

    const p3: KochPoint = {
      x: midX + height * perpX,
      y: midY + height * perpY
    };

    const points1 = this.calculateKochPoints(start, p1, iteration - 1);
    const points2 = this.calculateKochPoints(p1, p3, iteration - 1);
    const points3 = this.calculateKochPoints(p3, p2, iteration - 1);
    const points4 = this.calculateKochPoints(p2, end, iteration - 1);

    return [...points1.slice(0, -1), ...points2.slice(0, -1), ...points3.slice(0, -1), ...points4];
  }

  private generateSnowflakePoints(centerX: number, centerY: number, radius: number, iteration: number): KochPoint[] {
    const points: KochPoint[] = [];

    for (let i = 0; i < 3; i++) {
      const angle1 = (i * 2 * Math.PI) / 3 - Math.PI / 2;
      const angle2 = ((i + 1) * 2 * Math.PI) / 3 - Math.PI / 2;

      const start: KochPoint = {
        x: centerX + radius * Math.cos(angle1),
        y: centerY + radius * Math.sin(angle1)
      };

      const end: KochPoint = {
        x: centerX + radius * Math.cos(angle2),
        y: centerY + radius * Math.sin(angle2)
      };

      const segmentPoints = this.calculateKochPoints(start, end, iteration);
      points.push(...segmentPoints.slice(0, -1));
    }

    points.push(points[0]);
    return points;
  }

  private calculatePerimeter(iteration: number, initialLength: number): number {
    return initialLength * Math.pow(4 / 3, iteration);
  }

  private calculateArea(iteration: number, initialLength: number): number {
    const initialArea = (Math.sqrt(3) / 4) * initialLength * initialLength;
    let area = initialArea;
    for (let i = 0; i < iteration; i++) {
      area += (initialArea / Math.pow(3, 2 * i + 1)) * Math.pow(4, i);
    }
    return area;
  }

  private drawSnowflake(ctx: CanvasRenderingContext2D, iteration: number, progress: number = 1) {
    const centerX = this.canvasWidth / 2;
    const centerY = this.canvasHeight / 2;
    const radius = Math.min(this.canvasWidth, this.canvasHeight) * 0.4;

    const points = this.generateSnowflakePoints(centerX, centerY, radius, iteration);

    const visiblePoints = Math.floor(points.length * progress);

    if (visiblePoints < 2) return;

    ctx.strokeStyle = this.snowflakeColor;
    ctx.lineWidth = this.lineWidth;
    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';

    ctx.beginPath();
    ctx.moveTo(points[0].x, points[0].y);

    for (let i = 1; i < visiblePoints; i++) {
      ctx.lineTo(points[i].x, points[i].y);
    }

    ctx.stroke();

    if (this.showConstruction && iteration > 0) {
      this.drawConstructionLines(ctx, centerX, centerY, radius, iteration);
    }
  }

  private drawConstructionLines(ctx: CanvasRenderingContext2D, centerX: number, centerY: number, radius: number, iteration: number) {
    ctx.strokeStyle = '#E0E0E0';
    ctx.lineWidth = 0.5;
    ctx.setLineDash([3, 3]);

    for (let i = 0; i < 3; i++) {
      const angle1 = (i * 2 * Math.PI) / 3 - Math.PI / 2;
      const angle2 = ((i + 1) * 2 * Math.PI) / 3 - Math.PI / 2;

      const start: KochPoint = {
        x: centerX + radius * Math.cos(angle1),
        y: centerY + radius * Math.sin(angle1)
      };

      const end: KochPoint = {
        x: centerX + radius * Math.cos(angle2),
        y: centerY + radius * Math.sin(angle2)
      };

      ctx.beginPath();
      ctx.moveTo(start.x, start.y);
      ctx.lineTo(end.x, end.y);
      ctx.stroke();
    }

    ctx.setLineDash([]);
  }

  private drawCanvas() {
    const ctx = this.canvasContext;
    const width = this.canvasWidth;
    const height = this.canvasHeight;

    ctx.clearRect(0, 0, width, height);

    ctx.fillStyle = '#FAFAFA';
    ctx.fillRect(0, 0, width, height);

    this.drawSnowflake(ctx, this.iteration, this.animationProgress);

    this.drawGrid(ctx);
  }

  private drawGrid(ctx: CanvasRenderingContext2D) {
    const width = this.canvasWidth;
    const height = this.canvasHeight;

    ctx.strokeStyle = '#E0E0E0';
    ctx.lineWidth = 1;

    for (let x = 0; x <= width; x += 50) {
      ctx.beginPath();
      ctx.moveTo(x, 0);
      ctx.lineTo(x, height);
      ctx.stroke();
    }

    for (let y = 0; y <= height; y += 50) {
      ctx.beginPath();
      ctx.moveTo(0, y);
      ctx.lineTo(width, y);
      ctx.stroke();
    }
  }

  private startAnimation() {
    if (this.isAnimating) return;

    this.isAnimating = true;
    this.animationProgress = 0;

    const duration = 2000;
    const startTime = Date.now();

    const animate = () => {
      const elapsed = Date.now() - startTime;
      this.animationProgress = Math.min(1, elapsed / duration);
      this.drawCanvas();

      if (this.animationProgress < 1) {
        setTimeout(animate, 16);
      } else {
        this.isAnimating = false;
      }
    };

    animate();
  }

  private reset() {
    this.isAnimating = false;
    this.animationProgress = 1;
    this.drawCanvas();
  }

  private updateIteration(value: number) {
    this.iteration = value;
    this.reset();
  }

  build() {
    Column({ space: 15 }) {
      Text('科赫雪花')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .fontColor('#2196F3')
        .margin({ top: 10 })

      Text('迭代绘制科赫雪花,展示有限面积、无限周长的数学悖论。科赫雪花是由瑞典数学家海里格·冯·科赫于1904年提出的一种分形曲线,具有惊人的特性:在有限的空间内可以拥有无限长的周长。')
        .fontSize(14)
        .fontColor('#666')
        .textAlign(TextAlign.Center)
        .padding({ left: 15, right: 15 })

      Scroll() {
        Column({ space: 15 }) {
          Column({ space: 10 }) {
            Text('控制面板')
              .fontSize(18)
              .fontWeight(FontWeight.Bold)
              .fontColor('#333')
              .width('100%')

            Column({ space: 5 }) {
              Text(`迭代次数:${this.iteration}`)
                .fontSize(14)
                .fontColor('#333')
                .width('100%')

              Slider({
                value: this.iteration,
                min: 0,
                max: this.maxIteration,
                step: 1,
                style: SliderStyle.OutSet
              })
                .width('100%')
                .blockColor('#2196F3')
                .trackColor('#E3F2FD')
                .selectedColor('#2196F3')
                .showSteps(true)
                .onChange((value: number) => {
                  this.updateIteration(value);
                })
            }
            .width('100%')
            .padding(10)
            .backgroundColor('#F5F5F5')
            .borderRadius(8)

            Row({ space: 15 }) {
              Toggle({ type: ToggleType.Switch, isOn: this.showConstruction })
                .selectedColor('#2196F3')
                .onChange((isOn: boolean) => {
                  this.showConstruction = isOn;
                  this.drawCanvas();
                })

              Text('显示构造线')
                .fontSize(14)
                .fontColor('#333')
            }
            .width('100%')
            .justifyContent(FlexAlign.Start)
          }
          .width('100%')
          .padding(15)
          .backgroundColor('#FAFAFA')
          .borderRadius(10)

          Column({ space: 10 }) {
            Text('科赫雪花')
              .fontSize(18)
              .fontWeight(FontWeight.Bold)
              .fontColor('#333')
              .width('100%')

            Canvas(this.canvasContext)
              .width(this.canvasWidth)
              .height(this.canvasHeight)
              .backgroundColor('#FFFFFF')
              .border({ width: 2, color: '#333' })
              .borderRadius(4)
              .onReady(() => {
                this.reset();
              })
          }
          .width('100%')
          .padding(15)
          .backgroundColor('#FAFAFA')
          .borderRadius(10)

          Row({ space: 10 }) {
            Button(this.isAnimating ? '绘制中...' : '开始绘制')
              .width('50%')
              .height(50)
              .backgroundColor(this.isAnimating ? '#9E9E9E' : '#2196F3')
              .fontSize(16)
              .enabled(!this.isAnimating)
              .onClick(() => {
                this.startAnimation();
              })

            Button('重置')
              .width('50%')
              .height(50)
              .backgroundColor('#FF9800')
              .fontSize(16)
              .onClick(() => {
                this.reset();
              })
          }
          .width('100%')

          Column({ space: 10 }) {
            Text('数学特性')
              .fontSize(18)
              .fontWeight(FontWeight.Bold)
              .fontColor('#333')
              .width('100%')

            Column({ space: 5 }) {
              Row({ space: 10 }) {
                Text('当前迭代:')
                  .fontSize(14)
                  .fontColor('#333')
                  .width(100)

                Text(this.iteration.toString())
                  .fontSize(16)
                  .fontWeight(FontWeight.Bold)
                  .fontColor('#2196F3')
                  .layoutWeight(1)
              }
              .width('100%')

              Row({ space: 10 }) {
                Text('边数:')
                  .fontSize(14)
                  .fontColor('#333')
                  .width(100)

                Text((3 * Math.pow(4, this.iteration)).toString())
                  .fontSize(16)
                  .fontWeight(FontWeight.Bold)
                  .fontColor('#4CAF50')
                  .layoutWeight(1)
              }
              .width('100%')

              Row({ space: 10 }) {
                Text('周长倍数:')
                  .fontSize(14)
                  .fontColor('#333')
                  .width(100)

                Text(Math.pow(4 / 3, this.iteration).toFixed(4) + 'x')
                  .fontSize(16)
                  .fontWeight(FontWeight.Bold)
                  .fontColor('#E91E63')
                  .layoutWeight(1)
              }
              .width('100%')

              Row({ space: 10 }) {
                Text('面积倍数:')
                  .fontSize(14)
                  .fontColor('#333')
                  .width(100)

                Text((1 + (3 / 5) * (1 - Math.pow(4 / 9, this.iteration))).toFixed(4) + 'x')
                  .fontSize(16)
                  .fontWeight(FontWeight.Bold)
                  .fontColor('#9C27B0')
                  .layoutWeight(1)
              }
              .width('100%')
            }
            .width('100%')
            .padding(10)
            .backgroundColor('#F5F5F5')
            .borderRadius(8)
          }
          .width('100%')
          .padding(15)
          .backgroundColor('#FAFAFA')
          .borderRadius(10)

          Column({ space: 10 }) {
            Text('数学悖论')
              .fontSize(18)
              .fontWeight(FontWeight.Bold)
              .fontColor('#333')
              .width('100%')

            Column({ space: 5 }) {
              Text('• 无限周长:当迭代次数趋近于无穷大时,科赫雪花的周长也趋近于无穷大')
                .fontSize(14)
                .fontColor('#666')
                .width('100%')

              Text('• 有限面积:尽管周长无限,但科赫雪花的面积始终有限,收敛于初始三角形面积的8/5倍')
                .fontSize(14)
                .fontColor('#666')
                .width('100%')

              Text('• 分形维度:科赫雪花的分形维度为log(4)/log(3)≈1.26,介于1维和2维之间')
                .fontSize(14)
                .fontColor('#666')
                .width('100%')

              Text('• 自相似性:科赫雪花的任意局部都与整体相似,这是分形的基本特征')
                .fontSize(14)
                .fontColor('#666')
                .width('100%')
            }
            .width('100%')
            .padding(10)
            .backgroundColor('#F5F5F5')
            .borderRadius(8)
          }
          .width('100%')
          .padding(15)
          .backgroundColor('#FAFAFA')
          .borderRadius(10)

          Column({ space: 5 }) {
            Text('历史与应用')
              .fontSize(16)
              .fontWeight(FontWeight.Bold)
              .fontColor('#2196F3')

            Text('• 发现者:瑞典数学家海里格·冯·科赫(Helge von Koch)于1904年提出')
              .fontSize(12)
              .fontColor('#666')
              .width('100%')

            Text('• 数学意义:科赫雪花是最早被描述的分形曲线之一,是分形几何的经典例子')
              .fontSize(12)
              .fontColor('#666')
              .width('100%')

            Text('• 自然界应用:雪花、海岸线、山脉等自然现象都具有类似的分形特征')
              .fontSize(12)
              .fontColor('#666')
              .width('100%')

            Text('• 计算机图形:分形几何广泛应用于计算机图形学、图像压缩和艺术设计')
              .fontSize(12)
              .fontColor('#666')
              .width('100%')
          }
          .width('100%')
          .padding(15)
          .backgroundColor('#E3F2FD')
          .borderRadius(10)
        }
        .width('100%')
        .padding(10)
      }
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF')
  }
}
Logo

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

更多推荐