Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
975 views
in Technique[技术] by (71.8m points)

vb.net - Drawing and scaling rectangle using a ratio

I have a program where I can, with the mouse, draw a rectangle in any of four directions.

These rectangles are used on a pictureBox to crop parts of an image.

These rectangles must be drawn while maintaining the ratio of a given dimension for example 320 x 200.

I want this tool to behave pretty much exactly like the crop tool in Photoshop, or like in the crop example found here: https://imageresize.org/

I have most elements working correctly I'm just struggling on a few geometric calculations.

See the "Bottom right" example in my code. This works perfectly and basically I just want to apply this exact formula to the other directions.

I have been playing with different calculations for hours and I just can't seem to work it out.

Here is the working code:

 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

Any help would be hugely appreciated. Thanks!

Below is how things currently work, you can see things go funky when drawing in the north west region. I need to get the same behavior as the south east (or bottom right per the code) for all quadrants.

enter image description here

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You have sample rectangle S with given ratio and dimensions sw, sh (320x200 in your example)

Mouse positions form new rectangle N with dimensions nw, nh (absolute values!)

Your task is, as far as I understand, to inscribe rectangle with the same ratio as S into rectangle N, getting rectangle R with base point (rx0, ry0) and dimensions (rw, rh)

   nx0 = min(e.x, startpos.x) 
   ny0 = min(e.y, startpos.y) 
   nw = abs(e.x - startpos.x)
   nh = abs(e.y - startpos.y) 

   if nw * sh >= nh * sw then   //    if N is "too wide"
        rh = nh
        rw = rh * sw / sh
        ry0 = ny0                   
        rx0 = nx0 + (nw - rw) / 2
   else                        //      N is "too slim"
        rw = nw
        rh = rw * sh / sw
        rx0 = nx0
        ry0 = ny0 + (nh - rh) / 2

then

  mRect = New Rectangle(rx0,  ry0, rx0 + rw, ry0 + rh)

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...