Home > Blockchain >  Hold the writing direction inside the circle
Hold the writing direction inside the circle

Time:04-28

I draw lines that have a circle written inside the circle number 90. Now my problem is that the number 90 rotates with the rotation of the circle and becomes, for example, 09! How do I keep the writing direction constant? For example, always be down enter image description here

my codes are:

Imports System.Drawing.Drawing2D

Public Class Form1

    Private Segments As List(Of Segment) = New List(Of Segment)()
    Private NewSegment As Segment = Nothing
    Dim P As Pen = New Pen(Color.Black, 1.5)
    Dim CIRCLE, ELLIPSE As GraphicsPath
    Dim radius = 15
    Dim drawFontF As FontFamily = New FontFamily("times new roman")


    Private Sub PictureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseDown
        Dim drawString = "90"

        CIRCLE = New GraphicsPath()
        CIRCLE.AddEllipse(-15, 0, radius * 2, radius * 2)
        '****************************
        Dim angle = Math.Atan2(20 - e.Location.Y, 5 - e.Location.X)
        Dim x3 = 5   Math.Cos(angle) * radius
        Dim y3 = 20   Math.Sin(angle) * radius
        CIRCLE.AddString(drawString, drawFontF, FontStyle.Regular, 10, New Point(x3, y3), Nothing)

        P.CustomEndCap = New CustomLineCap(Nothing, CIRCLE)
        NewSegment = New Segment(P, e.Location, e.Location, "CIRCLE")

        PictureBox1.Refresh()
    End Sub

    Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
        If NewSegment Is Nothing Then Return
        NewSegment.pt2 = e.Location
        PictureBox1.Refresh()
    End Sub

    Private Sub PictureBox1_MouseUp(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseUp
        Dim PP As Pen = New Pen(Color.Black, 1.5)
        PP.CustomEndCap = New CustomLineCap(Nothing, CIRCLE)
        Dim H = "CIRCLE"

        NewSegment.pen1 = PP
        NewSegment.END_CAPS = H
        Segments.Add(NewSegment)
    End Sub

    Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
        e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias

        For Each segment As Segment In Segments
            segment.Draw(e.Graphics, Nothing, Nothing)
        Next

        If NewSegment IsNot Nothing Then
            NewSegment.Draw(e.Graphics, Nothing, Nothing)
        End If
    End Sub
End Class

Class Segment

    Public pen1 As Pen
    Public pt1, pt2 As Point
    Public END_CAPS As String


    Public Sub New(pen As Pen, point1 As Point, point2 As Point, END_CAP As String)
        pen1 = pen
        pt1 = point1
        pt2 = point2
        END_CAPS = END_CAP
    End Sub

    Public Sub Draw(gr As Graphics, R As Rectangle, INDEX As Integer)
        '*********************
        gr.SmoothingMode = SmoothingMode.AntiAlias

        gr.DrawLine(pen1, pt1, pt2)
    End Sub

End Class

CodePudding user response:

Personally, I'd just manually draw the "end cap" myself.

Also, I'd draw the segments themselves completely differently:

  1. Move the origin to the start point
  2. Rotate the surface around the new origin so the x-axis points to the end point
  3. Draw the segment as a line using only the translated and rotated x-axis

This setup allows us to draw the circle and 90 easier:

  1. Move the origin a little further out, along the still rotated x-axis, to the center of the circle.
  2. Draw the circle at the origin.
  3. Move the origin a little further out, halfway between the center of the circle and the edge of the circle.
  4. Rotate around the origin so that the 90 will be drawn "upright".
  5. Draw the 90.

Before we do steps 1-8, we save the current state of the graphics so we can "reset" after each segment draw and repeat the process for the next one.

Sample run:

enter image description here

Example code:

Public Class Form1

    Private NewSegment As Segment
    Private Segments As New List(Of Segment)

    Private Sub PictureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseDown
        NewSegment = New Segment(e.Location, e.Location)
        Segments.Add(NewSegment)
        PictureBox1.Invalidate()
    End Sub

    Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
        If NewSegment Is Nothing Then Return
        NewSegment.Point2 = e.Location
        PictureBox1.Invalidate()
    End Sub

    Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
        e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
        For Each segment As Segment In Segments
            segment.Draw(e.Graphics)
        Next
    End Sub

    Private Sub PictureBox1_MouseUp(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseUp
        NewSegment = Nothing
    End Sub

    Private Sub PictureBox1_SizeChanged(sender As Object, e As EventArgs) Handles PictureBox1.SizeChanged
        PictureBox1.Invalidate()
    End Sub

End Class

Class Segment

    Private pt1, pt2 As Point
    Private angle As Double = 0
    Private length As Double = 0

    Private Shared SF As StringFormat
    Private Const RADIUS As Integer = 20
    Private Shared drawString As String = "90"
    Private Shared pen1 As New Pen(Color.Black, 1.5)
    Private Shared drawFontF As New Font("times new roman", 10)
    Private Shared rc As New Rectangle(New Point(-RADIUS, -RADIUS), New Size(RADIUS * 2, RADIUS * 2))

    Public Sub New(startPoint As Point, endPoint As Point)
        Point1 = startPoint
        Point2 = endPoint
    End Sub

    Public Property Point1 As Point
        Get
            Return pt1
        End Get
        Set(value As Point)
            pt1 = value
            UpdateAngleAndLength()
        End Set
    End Property

    Public Property Point2 As Point
        Get
            Return pt2
        End Get
        Set(value As Point)
            pt2 = value
            UpdateAngleAndLength()
        End Set
    End Property

    Private Sub UpdateAngleAndLength()
        angle = Math.Atan2(Point2.Y - Point1.Y, Point2.X - Point1.X) * 180.0 / Math.PI
        length = Math.Sqrt(Math.Pow(Point2.X - Point1.X, 2)   Math.Pow(Point2.Y - Point1.Y, 2))
    End Sub

    Public Sub Draw(gr As Graphics)
        If IsNothing(SF) Then
            SF = New StringFormat()
            SF.Alignment = StringAlignment.Center
            SF.LineAlignment = StringAlignment.Center
        End If

        ' save the current state of the graphics
        Dim curState As GraphicsState = gr.Save()

        ' move the origin to the start point of the line
        gr.TranslateTransform(Point1.X, Point1.Y)
        ' rotate the whole surface
        gr.RotateTransform(angle)

        ' draw the line on the x-axis
        gr.DrawLine(pen1, 0, 0, CInt(length), 0)

        ' move the origin along the x-axis to where the center of the circle should be
        gr.TranslateTransform(length   RADIUS, 0)
        ' draw the circle
        gr.DrawEllipse(pen1, rc)

        ' draw the 90 at the opposite end of the circle, 
        ' at 3/4ths of the way to the opposite side,
        ' but still oriented downwards like "normal"
        gr.TranslateTransform(RADIUS / 2.0, 0) ' midway between center and opposite side of circle
        ' orient back to the "normal" so the 90 is upright
        gr.RotateTransform(-angle)
        ' draw the 90
        gr.DrawString(drawString, drawFontF, Brushes.Black, rc, SF)

        ' put the graphics back to the way it was originally
        gr.Restore(curState)
    End Sub

End Class
  • Related