投稿者 魔界の仮面弁士  (社会人) 投稿日時 2019/9/21 14:27:51
> 正多角形の頂点数N(3以上)
> 正多角形の外接円の中心座標O
> 正多角形の第一頂点の座標P
>あるいは、
> 正多角形の頂点数N(3以上)
> 正多角形の外接円の中心座標O
> 正多角形の外接円の半径R
> 正多角形の第一頂点の中心角θ

先の例は、後者のパラメータで描いたものですが、
マウスドラッグなどで描く場合は前者の方が楽かも。

Option Strict On
Imports System.Drawing.Drawing2D

Public Class Form1
  ''' <summary>正多角形の頂点座標を取得します。</summary> 
  ''' <param name="number">頂点数</param> 
  ''' <param name="origin">中心座標</param> 
  ''' <param name="point">第一頂点座標</param> 
  ''' <returns><see cref="number"/>個の要素をもつ一次元配列</returns> 
  Public Shared Function GetRegularPolygonF(number As Integer, origin As PointF, point As PointF) As PointF()
    If number < 3 Then
      Throw New ArgumentOutOfRangeException("number", number, "3 以上を指定してください。")
    End If
    Dim radian As Double = Math.Atan2(point.Y - origin.Y, point.X - origin.X)
    Dim radius As Double = (point.X - origin.X) / Math.Cos(radian)
    Dim vertex(number - 1) As PointF
    Dim theta As Double = Math.PI * 2.0R / number
    For n = 0 To number - 1
      Dim d As Double = n * theta + radian
      vertex(n).X = origin.X + CSng(radius * Math.Cos(d))
      vertex(n).Y = origin.Y + CSng(radius * Math.Sin(d))
    Next
    Return vertex
  End Function

  ''' <summary>多角形の頂点の数。NumericUpDown1 で変更する。</summary> 
  Public Property VertexCount As Integer = 7
  ''' <summary>中心座標。PictureBox1 を左クリックして指定する。</summary> 
  Public Property Origin As Nullable(Of Point)
  ''' <summary>頂点座標。PictureBox1 を左ドラッグして指定する。</summary> 
  Public Property Vertex As Point

  Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    NumericUpDown1.DataBindings.Add("Value"Me"VertexCount"False, DataSourceUpdateMode.OnPropertyChanged)
  End Sub

  Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
    If Origin IsNot Nothing Then
      Render(e.Graphics, draft:=True)
    End If
  End Sub

  Private Sub PictureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseDown
    If e.Button.HasFlag(MouseButtons.Left) Then
      Origin = e.Location
      Vertex = e.Location
    End If
  End Sub
  Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
    If e.Button.HasFlag(MouseButtons.Left) Then
      Vertex = e.Location
      PictureBox1.Invalidate()
    End If
  End Sub

  Private Sub PictureBox1_MouseUp(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseUp
    If Origin Is Nothing Then
      Return
    End If
    Vertex = e.Location

    '描画した多角形は累積して重ねていきたいので 
    'PictureBox に直接描画するのではなく、Image プロパティに残す 
    Dim newImage As Image
    Dim oldImage = PictureBox1.Image
    Dim rect = PictureBox1.ClientRectangle
    If oldImage Is Nothing Then
      newImage = New Bitmap(rect.Width, rect.Height)
    Else
      newImage = New Bitmap(Math.Max(oldImage.Width, rect.Width), Math.Max(oldImage.Height, rect.Height))
    End If

    Using g = Graphics.FromImage(newImage)
      g.Clear(Color.Transparent)
      If oldImage IsNot Nothing Then
        g.DrawImage(oldImage, Point.Empty)
      End If
      Render(g, draft:=False)
    End Using

    PictureBox1.Image = newImage
    Origin = Nothing

    If oldImage IsNot Nothing Then
      oldImage.Dispose()
    End If
  End Sub

  '多角形の描画 
  Private Sub Render(g As Graphics, draft As Boolean)
    Try
      Dim state = g.Save()
      g.SmoothingMode = SmoothingMode.HighQuality
      g.PixelOffsetMode = PixelOffsetMode.HighQuality

      If Origin.HasValue Then
        Using redPen As New Pen(If(draft, Brushes.Salmon, Brushes.Red), 3)
          g.DrawPolygon(redPen, GetRegularPolygonF(VertexCount, Origin.Value, Vertex))
          If draft Then
            g.FillEllipse(Brushes.Salmon, Origin.Value.X - 3, Origin.Value.Y - 3, 5, 5)
          End If
        End Using
      End If
      g.Restore(state)
    Catch ex As Exception
    End Try
  End Sub
End Class