• 贝塞尔曲线


    贝塞尔曲线有着很多特殊的性质, 在图形设计和路径规划中应用都非常广泛, 我就是想在路径规划中贝塞尔曲线完全由其控制点决定其形状, n个控制点对应着n-1阶的贝塞尔曲线,并且可以通过递归的方式来绘制.

    画重点了啊: 递归 :2点确定一个点(随着t变化),3点确定2个点,4点确定3个点,5点确定4个点,无限延伸,就像二进制可以延伸出我们美丽计算机世界一样。

     

    一阶曲线:

    对于一阶贝塞尔曲线为我们可以看到是一条直线,通过几何知识,很容易根据t的值得出线段上那个点的坐标:

    一阶曲线就是很好理解, 就是根据t来的线性插值. P0表示的是一个向量 [x ,y], 其中x和y是分别按照这个公式来计算的.

    二阶贝塞尔:


    既然重点是递归, 那么二阶贝塞尔必然和一阶有关系.

    在平面内任选 3 个不共线的点,依次用线段连接。在第一条线段上任选一个点 D。计算该点到线段起点的距离 AD,与该线段总长 AB 的比例。
    根据上一步得到的比例,从第二条线段上找出对应的点 E,使得 AD:AB = BE:BC。

    这时候DE又是一条直线了, 就可以按照一阶的贝塞尔方程来进行线性插值了, t= AD:AE
    这时候就可以推出公式了.

    推公式的主图
    对应着上图绿色线段的左端点
    对应着上图绿色线段的右端点
    对应着绿色线段的一阶贝塞尔曲线(线性插值)整理一下公式, 得到二阶贝塞尔公式

     

    三阶贝塞尔曲线:

    二阶的贝塞尔通过在控制点之间再采点的方式实现降阶, 每一次选点都是一次的降阶.
    四个点对应是三次的贝塞尔曲线. 分别在 AB BC CD 之间采EFG点, EFG三个点对应着二阶贝塞尔, 在EF FG之间采集HI点来降阶为一阶贝塞尔曲线.


    高阶贝塞尔曲线:
    高阶的贝塞尔可以通过不停的递归直到一阶

    贝塞尔曲线 公式
    可以通过递归的方式来理解贝塞尔曲线, 但是还是给出公式才方便计算的.


    仔细看可以发现, 贝塞尔的参数B是二项式(t+(1-t))^n = (1)^n的展开公式. 划重点了: 系数是二项式的展开. 后面的很多的贝塞尔曲线的性质都可以用这个来解释

    贝塞尔曲线的导数

    变化一下贝塞尔公式:

     
     
    和上文中的公式相同, 但是有一些字母的替换, 表达习惯不同

    控制点是独立的, 因此求导是直接对u就行求导, 就是仅仅对参数项B进行求导.

     

    定义: Q0=n*(P1-P0), Q0=n*(P2-P1), Q0=n*(P3-P2),...Qn-1=n*(Pn-Pn-1), . 如果我们把Q当做一组新的控制点, 那么原贝塞尔的导数可以写成如下:

    导数还是贝塞尔曲线, 只不过是控制点是原来控制点的组合而已.


     

    以下是一个三阶贝塞尔曲线golang例子:

    package main

    import(
      "fmt"
      "image"
      "image/color"
      "image/png"
      "log"
      "os"
    )

    // Putpixel describes a function expected to draw a point on a bitmap at (x, y) coordinates.
    type Putpixel func(x, y int)

    func drawline(x0, y0, x3, y3 int, brush Putpixel) {
      x1 := 500
      y1 := 500

      x2 := 0
      y2 := 250

      for i := 0; i < 1000; i++ {
        t := float32(i) / 1000.0
        x := int((1.0 - t) * (1.0 - t) * (1.0 - t) * float32(x0) + 3.0 * t * (1 - t) * (1 - t) * float32(x1) + 3.0 * t * t * (1 - t) * float32(x2) + t * t * t * float32(x3))
        y := int((1.0 - t) * (1.0 - t) * (1.0 - t) * float32(y0) + 3.0 * t * (1 - t) * (1 - t) * float32(y1) + 3.0 * t * t * (1 - t) * float32(y2) + t * t * t * float32(y3))
        brush(x,y)
      }
    }

    func main() {
      dx := 500
      dy := 500

      img := image.NewNRGBA(image.Rect(0, 0, dx, dy))
      drawline(350, 250, 500, 250, func(x, y int) {
        img.Set(x, y, color.Black)
      })

      // 左右都画一条竖线
      for i := 0; i < dy; i++ {
        img.Set(0, i, color.Black)
        img.Set(dx - 1, i, color.Black)
      }

      imgcounter := 250
      imgfile, _ := os.Create(fmt.Sprintf("%03d.png", imgcounter))
      defer imgfile.Close()

      // 以PNG格式保存文件
      err := png.Encode(imgfile, img)
      if err != nil{
        log.Fatal(err)
      }
    }

  • 相关阅读:
    【软剑攻城队】团队介绍发布!
    【软剑攻城队】团队简介
    耿丹计科16-1大家庭
    便捷从使用git开始
    交流从选择coding.net开始
    相识从C语言开始
    川师2016上半年软件工程助教总结
    2016年川师大软件工程本科生博客地址列表
    川师大研究生2015级现代软件工程(2016春)
    SVN:Cleanup failed to process the following paths
  • 原文地址:https://www.cnblogs.com/hailong88/p/13080355.html
Copyright © 2020-2023  润新知