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.
2
Answers
You have sample rectangle S with given ratio and dimensions
sw, sh
(320×200 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)
then
I propose a slightly different method to calculate the current position of the cursor, when a Ratio is applied to the Rectangle dimensions.
You need of course to save the starting position of the Rectangle, using the MouseDown event of a Control, then track the Mouse movements, using the MouseMove event.
The current position of the Cursor is calculated as usual (swapping the current Cursor Location the and Starting Position when the Offsets are negative).
The only difference is the Height of the Rectangle, when the overall size is subject to a Ratio constraint.
In this case, the
Rectangle.Location.Y
is determined by theRectangle.Width / Ratio
measure. This becomes visible if theCursor.Location.Y
is above the starting location (Cursor.Location.Y <= StartingPosition.Y
). Just like in the code you posted.For the example, I’m using a custom Rectangle class that holds all the information needed to draw a shape, with or without a specific Ratio applied to its dimensions.
▶ Note that the
Ratio
is hard-coded to1.6
: it’s just to for testing, of course it can be set to anything else.Visual sample of the results:
The
DrawingRectangle
class:▶ Note: the class has an
Owner
property, referencing the current Control where the shape is drawn: this allows to use aList(Of DrawingRectangle)
with different controls at the same time.