CArc类

CArc类继承了CGElement类,定义圆弧的属性和圆心、起点、终点三点绘圆的方法。颜色、线型、线宽等属性以及指定绘图模式下的画笔参数获取函数从基类中继承,另外还要定义圆弧特有的圆心、起点和终点属性。从这3个点还可以计算出圆弧所在圆的半径以及起点和终点相对于圆心的方位角,所以可以提供分别定义这3个数据的属性,它们是只读的。

CArc类也有3个构造函数。除了无参构造函数和用已知圆弧构造新圆弧的构造函数外,还提供了利用给定的3个点构造圆弧的构造函数。其中,这3个点分别是指定的圆心、起点和另外一点。这另外一点不一定是圆弧的终点。为什么不直接指定终点呢?因为交互绘图的过程中,第1次单击鼠标左键时确定圆心,第2次单击鼠标左键时确定圆弧的起点,然后鼠标移动。该移动的过程中,鼠标的光标位置是不确定的,它不可能正好落在圆弧上。但这个点还是有价值的,因为利用它相对于圆心的方位角和根据前两个点得到的半径,可以将这个点对应的终点计算出来。这个问题可以抽象为已知方向和距离,求直线段上一点坐标的问题。下面的代码中给出了解答。

CArc类用到多个数学函数,用VB.NET编程时,需要导入System.Math名字空间。

code.vb.net
'圆弧类
Imports System.Math
Public Class CArc
    Inherits CGElement
    Private m_Center,m_Begin, m_End As PointF"
    '圆心属性
    Public Property Center() As Pointf
        Get
            Return m_Center
        End Get
        Set(By Val Value As Pointf)
            m_Center = Value
        End Set
    End Property
    '圆弧起点属性
    Public Property ABeginO As Pointf
        Get
            Return m_Begin
        End Get
        Set(ByVal Value As Pointf)
            m_Begin = Value
        End Set
    End Property
    '圆弧终点属性
    Public Property Aend() As Pointf
        Get
            Return m_End
        End Get
        Set(ByVal Value As Pointf)
            m_End = Value
        End Set
    End Property
    '圆弧半径属性,只读
    Public ReadOnly Property Radius() As Single
        Get
            Dim r As Single
            r= distPtoP(m_Center, m_Begin)
            Return r
        End Get
    End Property
    '圆弧起点的方位角"
    Public ReadOnly Property AngleBegin() As Single
        Get
            Dim aAngle As Single
            aAngle = GetAngle(m_Center,m_Begin)
            Return aAngle
        End Get
    End Property
    '圆弧终点的方位角
    Public ReadOnly Property AngleEnd() As Single
        Get
            Dim aAngle As Singl
            aAngle = GetAngle(m_Center,m_End)
            Return aAngle
        End Get
    End Property
    '无参构造函数
    Public Sub New()
        Init()
    End Sub
    '构造函数,用已知的圆心、起点和另一点进行构造
    Public Sub New(By Val pCenter As PointF, ByVal p1 As PointF, ByVal p2 As PointF)
        Init()
        m_Center = pCenter
        m_Begin =p1
        Dim r As Single = DistProP(m_Center,m_Begin)
        Dim angle2 As Single = GetAngle(m_Center,p2)
        m_End.X=r*Cos(angle2) +m_Center.X
        m_End.Y=r*Sin(angle2)+m_Center.Y
    End Sub
    '构造函数,用已知的一个圆弧进行构造
    Public Sub New(ByVal aArc As CArc)
        With aArc
            m_Center =.Center
            m_Begin =.ABegin
            m_End=.AEnd
        End With
    End Sub"
    '初始化圆弧
    Private Shadows Sub Init()
        MyBase.Init()
        With m_Center
            X=0
            Y=0
        End With
        m_Begin = m_Center
        m_ End = m_Center
End Sub
End Class

前面用圆心、起点和第3点构造圆弧的构造函数用到了GetAngle函数。该函数返回两点连线的方位角,即两点连线与X轴正向之间的夹角。计算方位角时需要比较两个点的横纵坐标,根据终点相.于起点的位置得到所求的角度。GetAngle_数的代码如下

code.vb.net
'计算点间连线与X轴正向之间的夹角
Public Function GetAngle(ByVal p As Point'ByVal b2 As Point)As Single
    Dim tansita, sita, dx As Single
    dx = Abs(p2.X- p1.X)
    If p2.X=p1.X Then dx = 0.0001
    tansita = Abs(p2.Y-p1.Y)/dx
    sita = Atan(tansita)
    '如果终点横坐标大于、等于起点横坐标,并且终点纵坐标大于、等于起点纵坐标
    If p2.X>=p1.X And p2.Y>=p1.Y Then
        Return sita
    '如果终点横坐标小于、等于起点横坐标,并且终点纵坐标大于、等于起点纵坐标
    ElseIf p2.X<=p1.X And p2.Y>=p1.Y Then
        Return PI - sita
    '如果终点横坐标小于、等于起点横坐标,并且终点纵坐标小于、等于起点纵坐标
    Elself p2.X<=p1.X And p2.Y<=p1.Y Then
        Return PI + sita
    '如果终点横坐标大于、等于起点横坐标,并且终点纵坐标小于,等于起点级坐标
    ElseIf p2.X>=p1.X And p2.Y<=p1.Y Then
        Return PI *2- sita
    End If
End Function"

CArc类还需要重写基类的Draw 方法,根据不同的绘图模式绘制圆弧。实现Draw 方法的过程与前面各类中的基本相同。绘制圆弧使用的是API函数Arc,可从Win32API类中调用该函数。

code.vb.net
'绘图
Public Overrides Sub Draw(ByValg As Graphics,By ValaDrawMode As geDrawMode)
    Dim aPen, oldP As Long
    '将控制点的坐标由通用坐标转换为页面坐标
    Dim ec As PointF = WorldtoPage(m_Center)
    Dim eb As PointF = WorldtoPage(m_Begin)
    Dim ee As PointF= WorldtoPage(m_ End)
    '获得当前绘图环境的句柄
    Dim hdc As IntPtr
    hdc =g.GetHdc()
    '设置画笔参数
    Dim penPara As Integer() = DrawSettings(hdc, aDrawMode)
    '创建画笔"
    aPen =Win32API.CreatePen(penPara(0),penPara(1),penPara(2)
    '把画笔选入绘图环境,并返回原来的画笔
    oldP = Win32API.SelectObject(hde, aPen)
    '用刚刚创建的画笔绘圆弧
    Win32API.Arc(hdc,ec.X- Radius,ec.Y+ Radius,_
        ec.X+ Radius, ec.Y - Radius,eb.X,eb.Y,ee.X,ee.Y)
    '把原来的画笔选入绘图环境
    Win32APL.SelectObject(hdc, oldP)
    '删除新创建的画笔
    Win32API.DeleteObject(aPen)
    '释放绘图环境句柄
    g.ReleaseHdc(hdc)
End Sub