vb.net - 使用比例绘制和缩放矩形

标签 vb.net winforms graphics geometry

我有一个程序,我可以用鼠标在四个方向中的任何一个方向绘制一个矩形。

这些矩形在图片框上用于裁剪图像的一部分。

绘制这些矩形时必须保持给定尺寸的比例,例如 320 x 200。

我希望这个工具的行为与 Photoshop 中的裁剪工具非常相似,或者像此处的裁剪示例一样: https://imageresize.org/

我的大多数元素都工作正常,我只是在一些几何计算上遇到困难。

请参阅我的代码中的“右下角”示例。这非常有效,基本上我只想将这个精确的公式应用到其他方向。

我已经玩了几个小时不同的计算,但我似乎无法解决。

这是工作代码:

 Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
    'Draw rectangle keeping aspect ratio
    If e.Button = Windows.Forms.MouseButtons.Left Then
        If e.X > startPos.X And e.Y > startPos.Y Then
            'Bottom right
            mRect = New Rectangle(mRect.Left, mRect.Top, e.X - mRect.Left, e.Y - mRect.Top)
            mRect.Size = New Size(mRect.Width, mRect.Width / Ratio.Text)
            If e.Y < mRect.Bottom Then
                mRect = Rectangle.FromLTRB(startPos.X, startPos.Y, e.X, e.Y)
                mRect.Size = New Size(mRect.Height * Ratio.Text, mRect.Height)
            End If
            Me.Invalidate()
        ElseIf e.X < startPos.X And e.Y > startPos.Y Then
            'Bottom left
            mRect = New Rectangle(e.X, startPos.Y, startPos.X - e.X, e.Y - startPos.Y)
            mRect.Size = New Size(mRect.Width, mRect.Width / Ratio.Text)
            Me.Invalidate()
        ElseIf e.X > startPos.X And e.Y < startPos.Y Then
            'Top right
            mRect = New Rectangle(startPos.X, e.Y, e.X - startPos.X, startPos.Y - e.Y)
            mRect.Size = New Size(mRect.Height * 1.6, mRect.Height)
            Me.Invalidate()
        ElseIf e.X < startPos.X And e.Y < startPos.Y Then
            'Top left
            mRect = New Rectangle(e.X, e.Y, startPos.X - e.X, startPos.Y - e.Y)
            mRect.Size = New Size(mRect.Width, mRect.Width / Ratio.Text)
            Me.Invalidate()
        End If
    End If
End Sub

任何帮助将不胜感激。谢谢!

以下是目前的工作方式,您可以看到在西北地区绘图时事情变得很有趣。我需要为所有象限获得与东南部(或代码右下角)相同的行为。

enter image description here

最佳答案

当将比率应用于矩形尺寸时,我提出了一种稍微不同的方法来计算光标的当前位置。

您当然需要使用控件的 MouseDown 事件保存矩形的起始位置,然后使用 MouseMove 事件跟踪鼠标移动。

光标的当前位置照常计算(当偏移量为负时,交换当前光标位置和起始位置)。

当整体大小受到比率约束时,唯一的区别是矩形的高度。
在这种情况下,Rectangle.Location.Y Rectangle.Width / Ratio 确定测量。如果 Cursor.Location.Y 则这变得可见 位于起始位置 ( Cursor.Location.Y <= StartingPosition.Y ) 之上。就像您发布的代码一样。

例如,我使用一个自定义 Rectangle 类,该类包含绘制形状所需的所有信息,无论是否对其尺寸应用了特定的比率。

▶ 请注意Ratio 被硬编码为 1.6 :这只是为了测试,当然可以设置为其他值。

结果的可视化示例:

Drawing Rectangle with ration

Private DrawingRects As List(Of DrawingRectangle) = New List(Of DrawingRectangle)()

Private Sub PicureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PicureBox1.MouseDown
    If e.Button = MouseButtons.Left Then
        DrawingRects.Add(New DrawingRectangle() With {
            .DrawingcColor = Color.LightGreen,
            .Location = e.Location,
            .Owner = CType(sender, Control),
            .Ratio = 1.6,
            .Size = Size.Empty,
            .StartPosition = e.Location
        })
    End If
End Sub

Private Sub PicureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PicureBox1.MouseMove
    If e.Button = MouseButtons.Left Then
        Dim rect As DrawingRectangle = DrawingRects.Last()
        If e.X < rect.StartPosition.X Then rect.Location = New Point(e.X, rect.Location.Y)
        If e.Y < rect.StartPosition.Y Then rect.Location = New Point(rect.Location.X, e.Y)

        Dim currentWidth As Integer = Math.Abs(rect.StartPosition.X - e.X)

        If rect.Ratio = 1.0F Then
            rect.Size = New Size(currentWidth, Math.Abs(rect.StartPosition.Y - e.Y))
        Else
            If rect.StartPosition.Y <= rect.Location.Y Then
                rect.Size = New Size(currentWidth, CType(Math.Abs(rect.StartPosition.X - e.X) / rect.Ratio, Integer))
            Else
                Dim currentHeight As Integer = CType(currentWidth / rect.Ratio, Integer)
                rect.Location = New Point(rect.Location.X, rect.StartPosition.Y - currentHeight)
                rect.Size = New Size(currentWidth, currentHeight)
            End If
        End If
        DrawingRects(DrawingRects.Count - 1) = rect

        DirectCast(sender, Control).Invalidate()
    End If
End Sub

Private Sub PicureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PicureBox1.Paint
    Dim canvas As Control = DirectCast(sender, Control)

    If DrawingRects.Count > 0 Then
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
        For Each rect As DrawingRectangle In DrawingRects
            If canvas IsNot rect.Owner Then Continue For
            Using pen As New Pen(rect.DrawingcColor, rect.PenSize)
                e.Graphics.DrawRectangle(pen, New Rectangle(rect.Location, rect.Size))
            End Using
        Next
    End If
End Sub

DrawingRectangle 类:

▶ 注意:该类有一个 Owner 属性,引用绘制形状的当前 Control:这允许使用 List(Of DrawingRectangle) 同时使用不同的控件。

Public Class DrawingRectangle
    Private rectAspect As SizeF = SizeF.Empty
    Private rectRatio As Single = 0F

    Public Property Owner As Control
    Public Property Location As Point
    Public Property Size As Size
    Public Property StartPosition As Point
    Public Property DrawingcColor As Color
    Public Property PenSize As Single

    Public Property Aspect() As SizeF
        Get
            Return rectAspect
        End Get
        Set(ByVal value As SizeF)
            Me.rectAspect = value
            SetAspectRatio(value)
        End Set
    End Property

    Public Property Ratio As Single
        Get
            Return rectRatio
        End Get
        Set(ByVal value As Single)
            rectRatio = value
            SetAspectRatio(value)
        End Set
    End Property

    Private Sub SetAspectRatio(aspect As SizeF)
        Me.rectRatio = aspect.Width / aspect.Height
    End Sub
    Private Sub SetAspectRatio(ratio As Single)
        Me.rectAspect = New SizeF(100, 100 / ratio)
    End Sub
End Class

关于vb.net - 使用比例绘制和缩放矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54703035/

相关文章:

vb.net - 在 FolderBrowserDialog 中显示文本框

c# - 多线程系统.Windows.图形

c# - 从查找表中获取特定值?

cocoa - 用 Cocoa 绘制散点图

algorithm - 丢弃视口(viewport)外的元素

c# - VB 和 C# 之间的绑定(bind)问题

vb.net - 修改 Devexpress 中主从网格中的列标题名称

c# - winform 中的 OnPaint - .NET Compact Framework 3.5

math - 如何从四元数旋转计算相反的 View ?

vb.net - ListView:通过鼠标拖动多选项目