现在想用三次贝塞尔曲线模拟一个悬链式方程(方程已知),因为一段三次贝塞尔曲线需要四个控制点
,现在知道起点P0和终点P3,可以根据方程式计算出曲线上若干点的坐标,怎么根据这些点计算出贝塞尔曲线上另外两个控制点P1,P2的坐标。另外,横坐标轴和纵坐标轴的比例不一样,是否需要对计算后的点进行转换

解决方案 »

  1.   

    如果方程已知没必要用贝塞尔曲线画吧,这样画出来的东西可能也有偏差。取一系列稍微密集的点用直线连起来就已经能画得很漂亮了。给你一段代码吧,这是我以前为了平缓连接一系列采样点而写的一个函数,不知道能不能符合你的要求'Function Bezier By FangHong    2002.2  CSDN-chewinggum
    '说明:
    '         该模块用于在指定
    '函数形式:
    '         Bezier(Obj , X() , Y() , PenStyle , Width , Color)
    '参数说明
    '         obj: 对象名,一个picture 控件的完整名,如 form1.pic1
    '         x(): 关键点的x坐表数组
    '         y(): 关键点的y坐表数组
    '         PenStyle: 画笔的式样 可以定义以下值
    '                  0 画出的是实线        _________
    '                  1 画出的是虚线        _ _ _ _ _  (Width必须是1)
    '                  2 画出的是点线        .......... (Width必须是1)
    '                  3 画出的是点划线      ._._._._._ (Width必须是1)
    '                  4 画出的是点-点-划线  .._.._.._..(Width必须是1)
    '                  5 不能画图
    '         width: 线的宽度,当不是1的时候 penstyle 无效
    '         color: 线的颜色,可以用RGB()函数定义Public Declare Function CreatePen& Lib "gdi32" (ByVal nPenStyle As Long, ByVal nWidth As Long, ByVal crColor As Long)
    Public Declare Function DeleteObject& Lib "gdi32" (ByVal hObject As Long)
    Public Declare Function SelectObject& Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long)
    Public Const PS_SOLID& = 0              '实线
    Private Declare Function PolyBezier& Lib "gdi32" (ByVal hdc As Long, lppt As POINTAPI, ByVal cPoints As Long)
    '描绘贝塞尔(Bezier)曲线。Private Type POINTAPI                       '关键点坐标结构
             X                   As Long        '点的x坐标
             Y                   As Long        '点的y坐标
    End Type
    Dim Points() As POINTAPI
    Dim ptNum As Integer                        '点的数量
    Sub Bezier(Obj As Object, X() As Long, Y() As Long, ByVal PenStyle As Long, ByVal Width As Long, ByVal Color As Long)    For i = LBound(X) To UBound(Y)                  '
            AddPoints X(i), Y(i)                        '添加数据点
        Next                                            '    DrawBezier Obj, PenStyle, Width, Color          '绘制贝塞尔曲线
        DrawBezier Obj, PenStyle, Width, ColorReDim Points(0): ptNum = 0
    End Sub
    Sub DrawBezier(Obj As Object, ByVal PenStyle As Long, ByVal Width As Long, ByVal Color As Long)
        Dim i As Integer
        Dim iCount As Integer
          NewPen& = CreatePen(PenStyle, Width, Color)
          OldPen& = SelectObject(Obj.hdc, NewPen&)
              iCount = 0
              For i = 1 To ptNum - 2
                 iCount = iCount + 1
                 If iCount = 4 And i >= 4 Then
                    Obj.ForeColor = vbWhite
                    PolyBezier Obj.hdc, Points(i - 3), 4
                    iCount = 1
                 End If
              Next
          SelectObject Obj.hdc, OldPen&
          DeleteObject NewPen&
    End SubSub AddPoints(X As Long, Y As Long)
    '增加关键点
        Dim Line1 As Double
        Dim Line2 As Double
        Dim Line3 As Double
        Dim X1 As Double
        Dim x2 As Double
        Dim Y1 As Double
        Dim y2 As Double
        Dim b As Double
        
        
        ReDim Preserve Points(ptNum + 2)
        If (ptNum + 3) / 3 >= 2 Then
            Points(ptNum).X = X - (X - Points(ptNum - 2).X) / 3
            Points(ptNum - 1).X = Points(ptNum - 2).X + (X - Points(ptNum - 2).X) / 3
        End If
        Points(ptNum).Y = Y
        If (ptNum + 3) / 3 >= 3 Then
            Line1 = (Points(ptNum - 2).Y - Y) / (Points(ptNum - 2).X - X)
            Line2 = (Points(ptNum - 2).Y - Points(ptNum - 5).Y) / (Points(ptNum - 2).X - Points(ptNum - 5).X)
            X1 = 1000 * Cos(Atn(Line1))
            Y1 = 1000 * Sin(Atn(Line1))
            x2 = 1000 * Cos(Atn(Line2))
            y2 = 1000 * Sin(Atn(Line2))
            Line3 = (x2 - X1) / (Y1 - y2)
            b = Points(ptNum - 2).Y - Line3 * Points(ptNum - 2).X
            Points(ptNum - 3).Y = Line3 * Points(ptNum - 3).X + b
            Points(ptNum - 1).Y = Line3 * Points(ptNum - 1).X + b
        End If
        Points(ptNum + 1).X = X
        Points(ptNum + 1).Y = Y
        Points(ptNum + 2).X = X
        Points(ptNum + 2).Y = Y
        ptNum = ptNum + 3      '每次确定三个点,三个点的位置一样,中间一个为起点
                                '或终点,其余两个用于控制End Sub
    调用举例    Dim a(10) As Long
        Dim b(10) As Long
        
        For i = 1 To 10
            Randomize
            a(i) = i * 50
            b(i) = i * 50 * Rnd
        Next
        Style = 0
        
        Bezier Form1.Picture1, a, b, Style, 1, RGB(255, 0, 0)
      

  2.   

    回chewinggum(口香糖·dotnet转型中):用点的方法我知道,主要是因为曲线要保存起来,考虑到用贝塞尔曲线拟合存储起来容易些,也便于用户编辑曲线,用点或是一系列直线段的话一方面:要存储的坐标点过多,另一方面:用户没有办法直接修改整条线,很不方便。所以想知道假定这就是一条贝塞尔曲线,知道曲线上几个点的坐标,能不能由这几个点坐标计算出贝塞尔曲线的控点坐标
      

  3.   

    下面一段代码有点不太明白
            Line3 = (x2 - X1) / (Y1 - y2)
            b = Points(ptNum - 2).Y - Line3 * Points(ptNum - 2).X
            Points(ptNum - 3).Y = Line3 * Points(ptNum - 3).X + b
            Points(ptNum - 1).Y = Line3 * Points(ptNum - 1).X + b
    我认为将Line3 = (x2 - X1) / (Y1 - y2)修改为Line3 = (Y1 - y2)/(x2 - X1)可能还好理解一点,还有一个问题:
            X1 = 1000 * Cos(Atn(Line1))
            Y1 = 1000 * Sin(Atn(Line1))
            x2 = 1000 * Cos(Atn(Line2))
            y2 = 1000 * Sin(Atn(Line2))
            中的1000有什么根据,为什么要乘以该系数