图形绘制视频教程见《【VB.NET】二维图形绘制》
假设我想在图纸上绘制一个管道接口处的圆环横截面图样,管道圆环接口的半径为220毫米,接口宽度为40毫米,接口上共有16个螺丝穿孔,穿孔圆环半径为15毫米,即绘制出如下的图形:
由以上图形分析后可以看到,绘制过程可以分为绘制一个半径为220像素(每像素对应一毫米)的大圆和16个半径为15像素的小圆。对于大圆我们可以通过调整绘制钢笔宽度为40像素来绘制;对于相同规格的小圆穿孔,我们可以先定义出共同的规格,然后通过16次图形位移变形来绘制。
1.首先建立一个Win Form窗体程序,在窗体的Paint事件处理程序中定义固定的常量值(假设我们要在图纸(60,60)处开始绘制这个大圆):
Const r1 As Integer = 220 '大环半径
Const r2 As Integer = 15 '环孔半径
Const w As Integer = 40 '环宽
Const start As Integer = 60 '图纸绘制起点X和Y值
2.我们先绘制大圆。
设置绘制钢笔颜色为黑色,宽度为环宽,钢笔对齐方式设置为居中对齐(居中为默认值,可以不用设置)。
Dim pen As New Pen(Color.Black, w)
pen.Alignment = PenAlignment.Center
分析可得绘制大圆所需的矩形框宽高分别为400像素,即(r1-40/2)*2,起点为(60+20,60+20),所以绘制大圆的矩形可定义为:
Dim bigRect As New Rectangle(startXY + 20, startXY + 20,
(r1 - 20) * 2, (r1 - 20) * 2)
最后绘制出大圆的图形:
e.Graphics.DrawEllipse(pen, bigRect)
3.我接着定义要绘制的小圆规格,为了便于画布的平移变形,我们先把小圆的圆心定义在图纸的左上角,即(0,0)这一点,所以要绘制的小圆的规格可写为:
Dim smallRect As New Rectangle(-r2, -r2, r2 * 2, r2 * 2)
如果绘制出来就是上图左上角显示的右下侧一小部分:
e.Graphics.DrawEllipse(Pens.Red, smallRect)
4.现在利用画布的平移变形,把小圆的圆心平移到大圆右侧的中间里面,即现在的圆心位置的p1X值为480,p1Y值为280:
Dim p1X As Single = bigRect.Width + (startXY + 20)
Dim p1Y As Single = CSng(bigRect.Height / 2) + (startXY + 20)
e.Graphics.TranslateTransform(p1X, p1Y)
e.Graphics.DrawEllipse(Pens.Red, smallRect)
进行以上位置的平移变形后,绘制出来就是下图结果:
5.绘制第二个穿孔小圆时,我们可以利用数学中的三角函数来计算。我们知道在一个直角三角形中,一个锐角的对边与直角三角形的斜边比率可以用此角的正弦值来表示(SinA=a/c),此角的直角边与斜边的比率可以用它的余弦值来表示(CosA=b/c)。因此在斜边和一个锐角已知的情况下,我们可以求得直角的两个直角边的长度:a = SinA*c,b=CosA*c。
而我们要绘制的16个小圆的圆心点位置,把大圆的整个圆心角(360°)分成了16个相同角度的锐角,我们知道对应360°圆心角的是2π,π在VB里是用System.Math.PI表示的,在VB里求余弦用System.Math.Cos函数,求正弦用System.Math.Sin函数。所以对于下图中第二个小圆的圆心(centerPointX,centerPointY)与第一个小圆的圆心(p1X,p1Y)之间对应的大圆的圆心角就为2π/16=π/8。i第二个小圆的圆心点坐标我们就可以这样求得:
Dim centerPointX As Single =
CSng(bigRect.Width / 2 + (startXY + 20) +(r1 - 20) * Cos(PI / 8))
Dim centerpointY As Single =
CSng(bigRect.Height / 2 + (startXY + 20) + (r1 - 20) * Sin(PI / 8))
将画布取消上次变形后,再将画布平移这个坐标值,绘制出的小圆就为上图中的第二个小圆位置:
e.Graphics.ResetTransform()
e.Graphics.TranslateTransform(centerPointX, centerpointY)
e.Graphics.DrawEllipse(Pens.Red, smallRect)
6.根据以上,第一个小圆的圆心点坐标也可以三角函数来求得:
Dim p1X As Single =
CSng(bigRect.Width / 2 + (startXY + 20) + (r1 - 20) * Cos(0))
Dim centerpointY As Single =
CSng(bigRect.Height / 2 + (startXY + 20) + (r1 - 20) * Sin(0))
Cos(0)=1,Sin(0)=0,所以:
Dim p1X As Single = CSng(bigRect.Width / 2 + (r1 - 20) + (startXY + 20))
Dim p1Y As Single = CSng(bigRect.Height / 2 + (startXY + 20))
r1-20就是bigRect.Width / 2,所以计算出的点(p1X,p1Y)与我们最初计算的值是一样的:
Dim p1X As Single = bigRect.Width + (startXY + 20)
Dim p1Y As Single = CSng(bigRect.Height / 2) + (startXY + 20)
因此对于16个小圆的圆心点坐标,都可以根据它在大圆上对应的圆心角angle的值,表达为这样的计算公式:
Dim centerPointX As Single =
CSng(bigRect.Width / 2 + (startXY + 20) +(r1 - 20) * Cos(angle))
Dim centerpointY As Single =
CSng(bigRect.Height / 2 + (startXY + 20) + (r1 - 20) * Sin(angle))
7.最后将画小圆变成填充小圆为白颜色,根据小圆圆心点的位置变化,利用一个For循环整理以上代码如下:
Imports System.Drawing.Drawing2D
Imports System.Math
Class Form1
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
Const r1 As Integer = 220 '大环半径
Const r2 As Integer = 15 '环孔半径
Const w As Integer = 40 '环宽
Const startXY As Integer = 60 '图纸绘制起点X和Y值
Dim bigRect As New Rectangle(startXY + 20, startXY + 20,
(r1 - 20) * 2, (r1 - 20) * 2)
Dim smallRect As New Rectangle(-r2, -r2, r2 * 2, r2 * 2)
Using pen As New Pen(Color.Black, w)
pen.Alignment = PenAlignment.Center
e.Graphics.DrawEllipse(pen, bigRect)
End Using
For angle As Single = 0 To 2 * PI Step PI / 8 '2π对应360°
Dim state As GraphicsState = e.Graphics.Save
Dim centerPointX As Single =
CSng(bigRect.Width / 2 + (startXY + 20) + (r1 - 20) * Cos(angle))
Dim centerpointY As Single =
CSng(bigRect.Height / 2 + (startXY + 20) + (r1 - 20) * Sin(angle))
e.Graphics.TranslateTransform(centerPointX, centerpointY)
e.Graphics.FillEllipse(Brushes.White, smallRect)
e.Graphics.Restore(state)
Next
End Sub
End Class
绘制出的图形边缘会有锯齿状斑驳,可以在上面第10行代码绘制图形之前,设置画布的顺滑模式为反锯齿,以便让图形边缘显得顺滑:
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
最后的效果为: