如何使用Visual Basic .NET 2绘制非常特定的环形扇区

时间:2014-09-17 09:31:34

标签: vb.net math

这个问题进一步推进了先前的question。在那个问题中,valter为我提供了一个非常好的答案,它使用两行代码来执行所有数学运算。我希望他也想尝试一下这个问题。即使它看起来很相似,但我还是无法使用任何数学工作。

我现在需要绘制完全相同的环形扇区,接受该问题中的OuterRadius变为Rectangle。我包含这个image来解释我的意思。您会注意到表示插入函数的Rectangle的红线。该图像实际上是我现在尝试生成的代码的屏幕截图。当然,大多数都是错误的,但例如左上角的环形扇区是正确的。所有环形扇区应终止于矩形边缘,同时补偿间隙。转角案件可能需要3分。

我已经决定发布我到目前为止的代码,所以清教徒们必须闭上眼睛,因为它非常野蛮:

<Extension()> Friend Sub AddAnnularSector(
    ByVal aGraphicsPath As GraphicsPath,
    ByVal aCenterPoint As PointR,
    ByVal aInnerRadius As Double,
    ByVal aOuterRectangle As RectangleF,
    ByVal aStartAngle As Double,
    ByVal aSweepAngle As Double,
    ByVal aStartGap As Double,
    ByVal aEndGap As Double)
    'Declare local variables...
    Dim tInnerStartOffset As Double = (Math.Asin(aStartGap / aInnerRadius) * 180.0R) / Math.PI
    Dim tInnerEndOffset As Double = (Math.Asin(aEndGap / aInnerRadius) * 180.0R) / Math.PI
    Dim tTestAngle1 As Double = aStartAngle + aSweepAngle - tInnerEndOffset
    If tTestAngle1 > 360.0R Then tTestAngle1 -= 360.0R
    If tTestAngle1 > 270.0R Then tTestAngle1 = 360.0R - tTestAngle1
    If tTestAngle1 > 180.0R Then tTestAngle1 -= 180.0R
    If tTestAngle1 > 90.0R Then tTestAngle1 = 180.0R - tTestAngle1
    Dim tOuterEndLength As Double = (Math.Min(aOuterRectangle.Width, aOuterRectangle.Height) / 2) / Math.Sin(tTestAngle1.ToRadians)
    Dim tTestAngle2 As Double = aStartAngle + tInnerStartOffset
    If tTestAngle2 > 360.0R Then tTestAngle2 -= 360.0R
    If tTestAngle2 > 270.0R Then tTestAngle2 = 360.0R - tTestAngle2
    If tTestAngle2 > 180.0R Then tTestAngle2 -= 180.0R
    If tTestAngle2 > 90.0R Then tTestAngle2 = 180.0R - tTestAngle2
    Dim tOuterStartLength As Double = (Math.Min(aOuterRectangle.Width, aOuterRectangle.Height) / 2) / Math.Sin(tTestAngle2.ToRadians)
    'Add the annular sector to the figure...
    aGraphicsPath.StartFigure()
    aGraphicsPath.AddArc(CSng(aCenterPoint.X - aInnerRadius), CSng(aCenterPoint.Y - aInnerRadius), CSng(aInnerRadius * 2.0R), CSng(aInnerRadius * 2.0R), CSng(aStartAngle + tInnerStartOffset), CSng(aSweepAngle - (tInnerStartOffset + tInnerEndOffset)))
    aGraphicsPath.AddLines(New PointF() {
        New PointF(CSng((aCenterPoint.X) + (Math.Cos((aStartAngle + aSweepAngle - tInnerEndOffset).ToRadians) * tOuterEndLength)), CSng((aCenterPoint.Y) + (Math.Sin((aStartAngle + aSweepAngle - tInnerEndOffset).ToRadians) * tOuterEndLength))),
        New PointF(CSng((aCenterPoint.X) + (Math.Cos((aStartAngle + tInnerStartOffset).ToRadians) * tOuterStartLength)), CSng((aCenterPoint.Y) + (Math.Sin((aStartAngle + tInnerStartOffset).ToRadians) * tOuterStartLength)))
    })
    aGraphicsPath.CloseFigure()
    Return
End Sub

您将注意到上一个问题的OuterRadius如何更改为aOuterRectangle。内弧的绘制方式与先前绘制的外弧完全相同。

编辑1 :只需将代码切掉一点就可以使其更清晰。

编辑2 :这是一张实际需要的图片,与上面只显示当前结果的图片不同。

  • 浅青色 - 实际上将添加到GraphicsPath的图。
  • 深蓝色 - 由OuterRectangle切掉的图形部分。
  • 绿色 - OuterRectangle的尺寸,包括其中心点。
  • 黄色 - InnerRadius的尺寸,包括其中心点。
  • Pink - 在上一次调用该函数时添加的图片,其中包含不同的输入,仅供参考。

编辑3 :这image显示了我认为快速的数学解决方案。

由于

架式钻机

1 个答案:

答案 0 :(得分:0)

对于 wdthRect = 250,hgtRect = 200,innerR = 65,startA = 280.0,angle = 30.0,gap = 10.0R

enter image description here

Private Sub DrawAnnular2(ByVal pntC As Point, ByVal wdthRect As Integer, ByVal hgtRect As Integer, ByVal innerR As Integer, ByVal startA As Single, ByVal angle As Single, ByVal gap As Double)
    Dim g As Graphics
    Dim pth As New GraphicsPath
    Dim pthRct As New GraphicsPath
    Dim pthCrclIn As New GraphicsPath
    Dim pthCrclOut As New GraphicsPath
    Dim fe, theta, dbl As Double
    Dim outerR, wdth As Integer
    Dim rect As Rectangle

    wdth = Math.Min(wdthRect, hgtRect)

    outerR = CInt(Math.Sqrt(2.0R * (CDbl(wdth) / 2.0R) * (CDbl(wdth) / 2.0R))) 'πυθαγόρειο θεώρημα

    rect.X = CInt(CDbl(pntC.X) - CDbl(wdth) / 2.0R)
    rect.Y = CInt(CDbl(pntC.Y) - CDbl(wdth) / 2.0R)
    rect.Width = wdth
    rect.Height = wdth
    pthCrclOut.AddEllipse(pntC.X - outerR, pntC.Y - outerR, 2 * outerR, 2 * outerR)
    pthCrclIn.AddEllipse(rect)
    pthRct.AddRectangle(rect)

    '////// The same as annular 1 //////////////////////////////////////////////////
    g = Me.CreateGraphics
    g.SmoothingMode = SmoothingMode.AntiAlias

    gap /= 2.0R

    dbl = gap / CDbl(outerR)

    theta = Math.Asin(dbl) * 180.0R / Math.PI

    fe = theta

    pth.AddArc(pntC.X - outerR, pntC.Y - outerR, 2 * outerR, 2 * outerR, startA + CSng(fe), angle - CSng(2.0R * fe)) 'Outer

    dbl = gap / CDbl(innerR)

    theta = Math.Asin(dbl) * 180.0R / Math.PI

    fe = theta

    pth.AddArc(pntC.X - innerR, pntC.Y - innerR, 2 * innerR, 2 * innerR, startA + angle - CSng(fe), -(angle - CSng(2.0R * fe))) 'Inner

    '////////////////////////////////////////////////////////////

    Dim Reg1 As New Region(pth)

    Dim Reg2 As New Region(pthRct)

    Reg2.Intersect(Reg1)

    g.FillRegion(Brushes.Aqua, Reg2) 'This is the actual annular 2.
    g.DrawPath(Pens.Green, pthCrclIn)
    g.DrawPath(Pens.Green, pthCrclOut)
    g.DrawPath(Pens.Red, pthRct)

    Reg1.Dispose()
    Reg2.Dispose()
    pthRct.Dispose()
    pthCrclOut.Dispose()
    pthCrclIn.Dispose()
    pth.Dispose()
    g.Dispose()
End Sub

这行代码:

Reg2.Intersect(Reg1)

实际上是蓝色和红色之间的交叉

enter image description here

修改

Private Function DrawAnnular2(ByVal pntC As Point, ByVal wdthRect As Integer, ByVal hgtRect As Integer, ByVal innerR As Integer, ByVal startA As Single, ByVal angle As Single, ByVal gap As Double) As GraphicsPath
    Dim g As Graphics
    Dim pth As New GraphicsPath
    Dim pthRct As New GraphicsPath
    Dim pthFinal As New GraphicsPath
    Dim fe, theta, dbl As Double
    Dim outerR, wdth As Integer
    Dim rect As Rectangle
    Dim lst1 As New List(Of Integer)
    Dim lst2 As New List(Of Integer)
    Dim lst3 As New List(Of Integer)
    Dim lst4 As New List(Of Integer)
    Dim i As Integer
    Dim lstBl(3) As Boolean
    Dim position As Integer

    lstBl(0) = False
    lstBl(1) = False
    lstBl(2) = False
    lstBl(3) = False

    wdth = Math.Min(wdthRect, hgtRect)

    outerR = CInt(Math.Sqrt(2.0R * (CDbl(wdth) / 2.0R) * (CDbl(wdth) / 2.0R))) 'πυθαγόρειο θεώρημα

    rect.X = CInt(CDbl(pntC.X) - CDbl(wdth) / 2.0R)
    rect.Y = CInt(CDbl(pntC.Y) - CDbl(wdth) / 2.0R)
    rect.Width = wdth
    rect.Height = wdth
    pthRct.AddRectangle(rect)

    '////////////////////////////////////////////////////////
    g = Me.CreateGraphics
    g.SmoothingMode = SmoothingMode.AntiAlias

    gap /= 2.0R

    dbl = gap / CDbl(outerR)

    theta = Math.Asin(dbl) * 180.0R / Math.PI

    fe = theta

    If CDbl(angle) - 2.0R * fe >= 360.0R Then
        pthFinal.AddEllipse(pntC.X - innerR, pntC.Y - innerR, 2 * innerR, 2 * innerR)
        pthFinal.AddRectangle(rect)

        g.FillPath(Brushes.Aqua, pthFinal)
        g.DrawPath(Pens.Red, pthRct)

        pthRct.Dispose()
        pth.Dispose()
        g.Dispose()

        Return pthFinal
    End If

    pth.AddArc(pntC.X - outerR, pntC.Y - outerR, 2 * outerR, 2 * outerR, startA + CSng(fe), angle - CSng(2.0R * fe)) 'Outer

    dbl = gap / CDbl(innerR)

    theta = Math.Asin(dbl) * 180.0R / Math.PI

    fe = theta

    pth.AddArc(pntC.X - innerR, pntC.Y - innerR, 2 * innerR, 2 * innerR, startA + angle - CSng(fe), -(angle - CSng(2.0R * fe))) 'Inner

    '////////////////////////////////////////////////////////////


    For i = rect.X To rect.X + wdth
        If pth.IsVisible(i, rect.Y) Then
            If lst1.Count <> 0 Then
                If i <> lst1(lst1.Count - 1) + 1 Then
                    lstBl(0) = True
                    position = lst1.Count
                End If
            End If

            lst1.Add(i)
        End If
    Next

    For i = rect.Y To rect.Y + wdth
        If pth.IsVisible(rect.X + wdth, i) Then
            If lst2.Count <> 0 Then
                If i <> lst2(lst2.Count - 1) + 1 Then
                    lstBl(1) = True
                    position = lst2.Count
                End If
            End If

            lst2.Add(i)
        End If
    Next

    For i = rect.X To rect.X + wdth
        If pth.IsVisible(i, rect.Y + wdth) Then
            If lst3.Count <> 0 Then
                If i <> lst3(lst3.Count - 1) + 1 Then
                    lstBl(2) = True
                    position = lst3.Count
                End If
            End If

            lst3.Add(i)
        End If
    Next

    For i = rect.Y To rect.Y + wdth
        If pth.IsVisible(rect.X, i) Then
            If lst4.Count <> 0 Then
                If i <> lst4(lst4.Count - 1) + 1 Then
                    lstBl(3) = True
                    position = lst4.Count
                End If
            End If

            lst4.Add(i)
        End If
    Next


    'If lstBl(0) = True Or lstBl(1) = True Or lstBl(2) = True Or lstBl(3) = True Then
        'It is a rare case that i have to work on, when angle is too large
        'MsgBox(lstBl(0).ToString + " " + lstBl(1).ToString + " " + lstBl(2).ToString + " " + lstBl(3).ToString + " ")

        'Application.Exit()
    'End If

    'TextBox1.Text = lst1.Count.ToString + " " + lst2.Count.ToString + " " + lst3.Count.ToString + " " + " " + lst4.Count.ToString

    pthFinal.AddArc(pntC.X - innerR, pntC.Y - innerR, 2 * innerR, 2 * innerR, startA + angle - CSng(fe), -(angle - CSng(2.0R * fe))) 'Inner

    If CDbl(startA) + fe >= 225.0R And CDbl(startA) + fe <= 315.0R Then '1
        If lst1.Count <> 0 Then
            If lstBl(0) = True Then
                pthFinal.AddLine(lst1(position), rect.Y, lst1(lst1.Count - 1), rect.Y)
            Else
                pthFinal.AddLine(lst1(0), rect.Y, lst1(lst1.Count - 1), rect.Y)
            End If
        End If
        If lst2.Count <> 0 Then
            pthFinal.AddLine(lst1(lst1.Count - 1), rect.Y, rect.X + wdth, lst2(lst2.Count - 1))
        End If
        If lst3.Count <> 0 Then
            pthFinal.AddLine(rect.X + wdth, lst2(lst2.Count - 1), lst3(0), rect.Y + wdth)
        End If
        If lst4.Count <> 0 Then
            pthFinal.AddLine(lst3(0), rect.Y + wdth, rect.X, lst4(0))
        End If
        If lstBl(0) = True Then
            pthFinal.AddLine(rect.X, lst4(0), lst1(position - 1), rect.Y)
        End If
    ElseIf (CDbl(startA) + fe > 315.0R And CDbl(startA) + fe <= 360.0R) Or _
           (CDbl(startA) + fe >= 0.0R And CDbl(startA) + fe <= 45.0R) Then '2

        If lst2.Count <> 0 Then
            If lstBl(1) = True Then
                pthFinal.AddLine(rect.X + wdth, lst2(position), rect.X + wdth, lst2(lst2.Count - 1))
            Else
                pthFinal.AddLine(rect.X + wdth, lst2(0), rect.X + wdth, lst2(lst2.Count - 1))
            End If
        End If
        If lst3.Count <> 0 Then
            pthFinal.AddLine(rect.X + wdth, lst2(lst2.Count - 1), lst3(0), rect.Y + wdth)
        End If
        If lst4.Count <> 0 Then
            pthFinal.AddLine(lst3(0), rect.Y + wdth, rect.X, lst4(0))
        End If
        If lst1.Count <> 0 Then
            pthFinal.AddLine(rect.X, lst4(0), lst1(lst1.Count - 1), rect.Y)
        End If
        If lstBl(1) = True Then
            pthFinal.AddLine(lst1(lst1.Count - 1), rect.Y, rect.X + wdth, lst2(position - 1))
        End If
    ElseIf CDbl(startA) + fe > 45.0R And CDbl(startA) + fe <= 135.0R Then '3
        If lst3.Count <> 0 Then
            If lstBl(2) = True Then
                pthFinal.AddLine(lst3(position - 1), rect.Y + wdth, lst3(0), rect.Y + wdth)
            Else
                pthFinal.AddLine(lst3(lst3.Count - 1), rect.Y + wdth, lst3(0), rect.Y + wdth)
            End If
        End If
        If lst4.Count <> 0 Then
            pthFinal.AddLine(lst3(0), rect.Y + wdth, rect.X, lst3(0))
        End If
        If lst1.Count <> 0 Then
            pthFinal.AddLine(rect.X, lst3(0), lst1(lst1.Count - 1), rect.Y)
        End If
        If lst2.Count <> 0 Then
            pthFinal.AddLine(lst1(lst1.Count - 1), rect.Y, rect.X + wdth, lst2(lst2.Count - 1))
        End If
        If lstBl(2) = True Then
            pthFinal.AddLine(rect.X + wdth, lst2(lst2.Count - 1), lst3(position), rect.Y + wdth)
        End If
    Else '4
        If lst4.Count <> 0 Then
            If lstBl(3) = True Then
                pthFinal.AddLine(rect.X, lst4(position - 1), rect.X, lst4(0))
            Else
                pthFinal.AddLine(rect.X, lst4(lst4.Count - 1), rect.X, lst4(0))
            End If
        End If
        If lst1.Count <> 0 Then
            pthFinal.AddLine(rect.X, lst4(0), lst1(lst1.Count - 1), rect.Y)
        End If
        If lst2.Count <> 0 Then
            pthFinal.AddLine(lst1(lst1.Count - 1), rect.Y, rect.X + wdth, lst2(lst2.Count - 1))
        End If
        If lst3.Count <> 0 Then
            pthFinal.AddLine(rect.X + wdth, lst2(lst2.Count - 1), lst3(0), rect.Y + wdth)
        End If
        If lstBl(3) = True Then
            pthFinal.AddLine(lst3(0), rect.Y + wdth, rect.X, lst4(position))
        End If
    End If


    'g.FillPath(Brushes.Blue, pth)
    g.FillPath(Brushes.Aqua, pthFinal)
    g.DrawPath(Pens.Red, pthRct)

    pthRct.Dispose()
    pth.Dispose()
    g.Dispose()

    Return pthFinal
End Function

你的价值观:

enter image description here