0

The project goal is to rotate the middle disk(RaobfMobile Picturebox)) backward into the in-outer disk(RaobfBG(PictureBox)) accordingly to the mouse location (holding left button) in order to read a result (red line) on a graduation circle.

RaobfDisk

This middle disk should stay backward of the in-out one in order to keep red lines over it and show a result on graduation. It must keep his initial center(470 :470) to rotate.

Video Drive link=> Raobf Project Video Clip (28s)

  • Issue 1 (1s => 18s)

How to keep correct disc center when moving the mifddle disc (noticeable in VideoClip). I thought code : Private picRCenter As New Point(470, 470) would do that.

  • Issue 2 (19s => video end)

When releasing left button, i lose mouse control on middle disc and can't move the middle disc anymore. Code : Using RaobfMobile.Capture = true in Form1_Load is not enough to trigger MouseMove event more than once.

  • Question :

Is it possible to define circle (instead of rectangle) Picturebox ? maybe more convenient to avoid center shift.

Note : - I will clear picture sources in final dev phase. - Sry for my average english wording.

Help would be greatly appreciated.

Public Class Form1
    Private WithEvents RaobfMobile As New PictureBox With {.Parent = Me, .Cursor = Cursors.Hand,
        .BackgroundImageLayout = ImageLayout.Center,
        .BackgroundImage = Image.FromFile("C:\Users\Grimsek\Documents\Wolfpack documentation\RAOBF Prj\RAOBFInner_transp.png"),
        .Location = New Point(0, 0), .Size = New Size(940, 940),
        .BackColor = Color.SteelBlue}
    Private WithEvents RaobfBG As New PictureBox With {.Parent = Me,
        .BackgroundImageLayout = ImageLayout.Center,
        .BackgroundImage = Image.FromFile("C:\Users\Grimsek\Documents\Wolfpack documentation\RAOBF Prj\RAOBFOuter_transp.png"),
        .Location = New Point(0, 0), .Size = New Size(940, 940),
        .BackColor = Color.SteelBlue}


    Private picRSize As New Size(940, 940)
    Private picRCenter As New Point(470, 470)
    Private angle As Double = 0

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        RaobfMobile.Controls.Add(RaobfBG)
        RaobfBG.Location = New Point(0, 0)
        RaobfBG.BackColor = Color.Transparent
        Text = "Rotation RAOBF"
        ClientSize = New Size(940, 940)
        DoubleBuffered = True

        SetRotated(RaobfMobile, CSng(angle))

        RaobfMobile.Capture = True


    End Sub
    Private Function GetAngle(ByVal ptFrom As PointF, ByVal ptTo As PointF) As Double
        Dim dx As Double = ptFrom.X - ptTo.X
        Dim dy As Double = ptFrom.Y - ptTo.Y
        Dim a As Double = 57.3 * Math.Atan2(dy, dx)
        If a > 360 Then angle -= 360
        If a < 0 Then angle += 360

        Return a
    End Function

    Private Sub picR_MouseMove(sender As Object, e As MouseEventArgs) Handles RaobfMobile.MouseMove

        If e.Button = MouseButtons.Left Then

            angle = GetAngle(e.Location, New Point(CInt(RaobfMobile.Bounds.Width / 2),
                                       CInt(RaobfMobile.Bounds.Height / 2)))

            SetRotated(RaobfMobile, CSng(angle))

            Refresh()
        End If
    End Sub

    Private Sub picR_Paint(sender As Object, e As PaintEventArgs) Handles RaobfMobile.Paint
        'draw the rotated image
        Using mx As New Matrix
            mx.RotateAt(CSng(angle), New PointF(CSng(RaobfMobile.ClientSize.Width / 2), CSng(RaobfMobile.ClientSize.Height / 2)))
            e.Graphics.Transform = mx
            Dim x As Integer = CInt((RaobfMobile.ClientSize.Width / 2) - (RaobfMobile.BackgroundImage.Width / 2))
            Dim y As Integer = CInt((RaobfMobile.ClientSize.Height / 2) - (RaobfMobile.BackgroundImage.Height / 2))
            e.Graphics.DrawImage(RaobfMobile.BackgroundImage, x, y,
                                 RaobfMobile.BackgroundImage.Width, RaobfMobile.BackgroundImage.Height)

        End Using
    End Sub

    Private Sub SetRotated(thePic As PictureBox, angle As Single)

        Using rg As New Region,
                mx As New Matrix,
                pth As New GraphicsPath

            'get the size of the rotated rect
            pth.AddRectangle(New RectangleF(0, 0, picRSize.Width, picRSize.Height))
            mx.RotateAt(angle, New PointF(CSng(picRSize.Width / 2), CSng(picRSize.Height / 2)))
            pth.Transform(mx)
            Dim rect As RectangleF = pth.GetBounds()

            'size the pict to fit the rect
            thePic.ClientSize = New Size(CInt(rect.Width + 1), CInt(rect.Height + 1))
            thePic.Location = New Point(CInt(picRCenter.X - thePic.ClientSize.Width / 2), CInt(picRCenter.Y - thePic.ClientSize.Height / 2))

            'remake the path rect at the new pic center and rotate
            pth.Reset()
            Dim x1 As Integer = CInt((thePic.ClientSize.Width / 2) - (picRSize.Width / 2))
            Dim y1 As Integer = CInt((thePic.ClientSize.Height / 2) - (picRSize.Height / 2))
            pth.AddRectangle(New RectangleF(x1, y1, picRSize.Width, picRSize.Height))
            mx.Reset()
            mx.RotateAt(angle, New PointF(CSng(thePic.ClientSize.Width / 2), CSng(thePic.ClientSize.Height / 2)))
            pth.Transform(mx)

            'add rotated path region to picturebox
            thePic.Region = New Region(pth)

        End Using
    End Sub
End Class
Grimsek
  • 1
  • 1
  • Keep the BackGround image. Rotate just the inner Bitmap. Calculate the angle using the mouse movement on the Y axis, applying a scale to determine how much the mouse movements increments the angle. Paint and rotate the inner Bitmap using just `matrix.RotateAt()`. The center of the canvas is, of course, fixed; it only changes if/when the container (the PictureBox is resized). – Jimi Apr 08 '19 at 12:42
  • @jimi _Keep the BackGround image. Rotate just the inner Bitmap_. Ok already coded => `SetRotated(RaobfMobile, CSng(angle))` _Calculate the angle using the mouse movement on the Y axis, applying a scale to determine how much the mouse movements increments the angle._ I thought `PictureBox.Bounds` in `Sub picR_MouseMove` should do it ? It looks like it's the square shape of Bitmap in the same square Form1 (same dimensions 940:940) which causes the center to shift, no ? thats why i asked if a way of disk shape Bitmap/PictureBox statement exists to avoid this issue. – Grimsek Apr 08 '19 at 13:25
  • If you need to rotate just the bitmap that defines the inner *circle*, you need to rotate just that Bitmap, keeping the BackgroundImage (the outer circles) fixed. You don't need a GraphicsPath and definitely not to set a Region. Use the mouse movement to change the angle and use the `matrixRotateAt()` method to draw the inner (transparent) bitmap. That's all. If you need to rotate both bitmaps, see the example here: [Transparent Overlapping Circular Progress Bars](https://stackoverflow.com/a/53379442/7444103) (C# code, but it's the same thing) – Jimi Apr 08 '19 at 13:45
  • ty @Jimi / I deleted the useless `SetRotated()` Sub It works fine : The `Refresh()` call the `Paint()`., inner Disk follow the Mousemove as i release mouse button.// Last medium issue : grabed disk is not the current disk rotate-shaped previous step. I think code reset disc "rotation" as of the first `Form1_Load()` On click event, it should keep the last Painted shaped step as start of the next rotation. I could save the `e.Graphics.Drawimage()` as Bitmap from Sub Paint(), but where should i initialise this new rotated shape as BmpSource for MouseMove() event ? – Grimsek Apr 09 '19 at 11:19

0 Answers0