Drawing Rectangles in Picture box Coordinate flip? - vb.net

So I have a picture box with an image. I have coordinates to draw certain boxes (as in multiple rectangles) on the image (from a device).
Dim rectPoint_Start As Point =
New Point((newStartPoint_X * pbZoneImage.Width / resWidth),
newStartPoint_Y * pbZoneImage.Height / resHeight)
Dim rectPoint_End As Point =
New Point((newEndPoint_X * pbZoneImage.Width / resWidth),
newEndPoint_Y * pbZoneImage.Height / resHeight)
Dim rectangleHeight As Integer = (rectPoint_End.Y - rectPoint_Start.Y)
Dim rectangleWidth As Integer = (rectPoint_End.X - rectPoint_Start.X)
'localize
camRect1 = New Rectangle(rectPoint_Start.X, rectPoint_Start.Y, _
rectangleWidth, rectangleHeight)
If camRect1 <> Nothing Then g.DrawRectangle(Pens.Blue, camRect1)
The rect coordinates are coming in scaled with a resolution, so you see me there changing it to a relative point value for the pbZoneImage picture box. The problem I am having is that the coordinates I'm receiving (from the device) are assuming the (0,0) point is in the bottom left, where the PB draws these boxes starting from the top left. Is there a way to change the orientation of the starting point being drawn in the g.drawRectangle()? Or another method.
What I have tried so far is to add (pbzoneImage.bottom) - ((newEndPoint_X * pbZoneImage.Width ....) in the rectPoint_End and rectPoint_Start points. It doesn't seem to work and gives me negative values.
Update:
So this is what I ended up doing to fix it. I ended up drawing out a coordinate system and doing some old school algebra based on some of the answers I received. (Reminder, pbZoneImage is a picture box, startpoint x and y along with endpoint x and y are the values from the device)
Dim rectangleHeight As Integer = Math.Floor((newEndPoint_Y - newStartPoint_Y) * pbZoneImage.Height)
Dim rectangleWidth As Integer = Math.Floor((newEndPoint_X - newStartPoint_X) * pbZoneImage.Height)
'flip rectangle
Dim rectPoint_Start As New Point((newStartPoint_X * pbZoneImage.Width), _
pbZoneImage.Height - (newStartPoint_Y * pbZoneImage.Height) - rectangleHeight)
Dim rectPoint_End As Point = New Point((newEndPoint_X * pbZoneImage.Width), _
pbZoneImage.Height - (newEndPoint_Y * pbZoneImage.Height) - rectangleHeight)
'localize
camRect1 = New Rectangle(rectPoint_Start.X, rectPoint_Start.Y, _
rectangleWidth, rectangleHeight)

Upon receiving newStartPoint_Y and newEndPoint_Y values from the device, do the following :
newStartPoint_Y = resHeight - newStartPoint_Y
newEndPoint_Y = resHeight - newEndPoint_Y
assuming your device gives you coordinates on a zero-based reference (where the point at the lower left corner has the coordinate (0,0) which would fit with the zero-based coordinates of the top left corner of a PictureBox)
If I understand well, newStartPoint_X/Y and newEndPoint_X/Y are coordinates directly from the device ?
I suggest you to take the habit to use either CInt() when using Point with integer X and Y values, or better : CSng() with PointF, since you're scaling coordinates anyway.

I believe you are forgetting to also adjust for the rectangle height. If the rectangle origin is the lower left and its position was mapped to the resized image coordinate system based upon image lower left origin then you must adjust for the resized image height and the mapped rectangle height. Sketch it out on paper to get the relationships right.

Related

Program first draws on invisible picturebox then picturebox becomes visible DESPITE Visibility supposed to c ome first then dynamic drawing

A snippet of my code:
Dim G As Graphics
Dim BBG As Graphics
Dim BB As Bitmap
Dim R As Rectangle
..................................................................
picMainScreen.Visible = True
G = picMainScreen.CreateGraphics
BB = New Bitmap(picMainScreen.Width, picMainScreen.Height)
For x = 0 To 256 * 3 - 1 Step 24
For y = 0 To 240 * 3 - 1 Step 24
R = New Rectangle(New Point(x, y), New Point(24, 24))
G.DrawRectangle(Pens.Black, R)
Next
Next
In this snippet of code, picMainScreen was a PictureBox that was originally not supposed to be visible.
Then through some conditions, picMainScreen was SUPPOSED to TURN Visible.
And THEN, the code draws all the rectangles onto the picture.
However, that isn't the case: the rectangles are first drawn onto the picture, and THEN the picture becomes visible.
Why does this happen? And what's the remedy?
Your rectangle instantiation is interesting since you are using two parameters of type Point.
R = New Rectangle(New Point(x, y), New Point(24, 24))
The Microsoft Docs show these parameter types;
Rectangle(Point, Size)
Initializes a new instance of the Rectangle class with the specified location and size.
https://learn.microsoft.com/en-us/dotnet/api/system.drawing.rectangle.-ctor?view=netframework-4.7.2
I'm not sure if the parameter types are the problem; however you are mixing drawing graphics with a picture control and they might not cohabitate in the same space well.
You could try calling DoEvents() after making the picture control visible to force it to be displayed first.

Setting the correct width of a child window

I have a parent window that has a panel on the left hand side into which some buttons are placed. There is also a splitter added, so that the user can adjust the size of this panel. When a user presses one of the buttons, a form should appear on the right hand size - defaulting to the width of the remaining area of the window. In order to work out how wide this child form needs to be, I have taken the client width and subtracted the width of the panel and the splitter from this, however it is always slightly too big. I can simply subtract an additional 4 from the calculation to get it to work - but this feels unstable to me, as I don't know where those 4 pixels have come form! How do I calculate this correctly. My Code is below.
Dim xPos As Integer = Me.Panel1.Width + Me.Splitter1.Width
Dim yPos As Integer = 0
Dim childFormWidth As Integer = Me.ClientSize.Width - xPos
Dim childFormHeight As Integer = 200
myChildForm.Show()
myChildForm.Location = New Point(xPos, yPos)
myChildForm.Size = New Size(ChildFormWidth, myHeight)
Thanks Paul.

Pairing Lat/Long coordinates to x/y coordinates of image in picture box

The core questions is: How do I interpolate 4 lat/long values paired to x/y coordinates across the entire image
For the ease of this question let's assume my image will be static.
I have a picture box with an image that has a
height of 638 pixels
width of 1024 pixels.
I have a geocoded tab file for this image that has lat/long pairs for x/y pairs along with the projection.
(-86.672304,36.132795) (443,30) Label "Pt 1",
(-86.672192,36.133032) (475,56) Label "Pt 2",
(-86.669807,36.13234) (286,290) Label "Pt 3",
(-86.670073,36.132034) (246,248) Label "Pt 4"
CoordSys Earth Projection 1, 104
Units "degree"
I'm trying to figure out how I take these 4 points and extend my lat/long to x/y conversion for each pixel.
I believe all I need to do now is apply some sort of scale. I can figure the delta between each of the points on a 2 dimensional plane but I'm not sure how to coordinate that.
I am using the following function to determine distance between points
Private Function distanceBetweenPoints(ByRef pt1x As Double, ByRef pt1y As Double, ByRef pt2x As Double, ByRef pt2y As Double)
Dim p1x As Double = pt1x
Dim p1y As Double = pt1y
Dim p2x As Double = pt2x
Dim p2y As Double = pt2y
Dim pointDelta As Double
Dim xDiff As Double = (p2x - p1x) ^ 2
Dim yDiff As Double = (p2y - p1y) ^ 2
pointDelta = Math.Sqrt(xDiff + yDiff)
Return pointDelta
End Function
and using it the following way
delta1 = distanceBetweenPoints(pt1x, pt1y, pt2x, pt2y)
So this will give me the distance in a straight line based on my lat and long.
If I do the same for my x/y pixel I should be able to get the pixel distance then I should be able to divide lat/long delta by pixel delta to get the width of each pixel.

One picture box shown many times in the same form

My Goal is to create a maze in VS using VB.net, I currently have managed to make a random Generator that makes the "maze" and shows the location of the last wall made.
Horizontalwalls = Randomizer.Next(60, 91) 'Makes 60 - 90 Horizontal Walls
VirticalWalls = Randomizer.Next(60, 91) 'Makes 60 -90 Vertical Walls
Dim HLoops = 0 'counter for Horizontal walls
Dim VLoops = 0
lbxHorizontal.Items.Clear() 'empties the list box i have which stores the walls location
lbxvertical.Items.Clear()
Do While HLoops < (Horizontalwalls)
HLoops += 1 'adds to the counter
lbxHorizontal.Items.Insert(0, Randomizer.Next(0, 10))
lbxHorizontal.Items.Insert(0, Randomizer.Next(0, 10))
'Attempt at making visable walls
pbxhorizontalwall.Top = (lbxHorizontal.Items.Item(0) * GridSize - 2) 'This and next line puts the wall in desired location
pbxhorizontalwall.Left = (lbxHorizontal.Items.Item(1) * GridSize - 2)
Loop
however the only way i know to make all the walls visible is to make 90 horizontal wall pictures, go though naming them all, then GLaaa... there must be a easier way to copy the same image over the screen at the desired location.
At the moment, all i really want to know is the line of code that will copy the image (and maybe a way to mass clear them all when the maze is reset) and then i'll work out how to get it into place...
You first create the list of images with:
Dim imageList As New List(Of Bitmap)
imageList.Add("image to add") 'do it for all the images you have
Then create a bitmap:
Dim bitmapWall as Bitmap = New Bitmap(widthOfbitmap, heightofbitmap, Drawing.Imaging.PixelFormat.Format24bppRgb)
Draw the list of images to the bimap:
Dim objGraphics As Graphics = Graphics.FromImage(bitmapWall)
For i = 0 To imageList.Count
objGraphics.DrawImage(imageList(i), x, y, imageList(i).Width, imageList(i).Height)
Next
objGraphics.Dispose()
x,y is the coordinates of where your images are drawn (you should change them for every iteration)
Lastly:
Me.BackgroundImage = bitmapWall
Me.Invalidate()
Dont forget to dispose the list and the bitmap in the end.
valter

Find total overlap percent of multiple rectangles overlapping the same rectangle?

I've got a list of System.Drawing.RectangleF objects that all overlap the same RectangleF object. In my picture below, the 3 overlapping rectangles would be the pink, yellow, and red rectangles. My main rectangle in question is the light blue rectangle.
Second Image:
I know that with RectangleF objects I can use the Intersect() method that will return me another RectangleF object representing the overlap. But as far as I can tell, this only really works when comparing two rectangles.
My question is: How could I determine the TOTAL area/percentage (i.e. the combined total overlap of the red, yellow, and pink rectangles when compared to the light blue rectangle - but it would need to be smart enough to not count the area in which the red and yellow overlaps twice, and same for the pink and yellow)?
NOTE: The green lines represent the area I'm looking for, just the total area of the blue rectangle that is not visible.
UPDATE: I've added a 2nd image to further demonstrate what I'm looking for. In the second image, the presence of the burgundy rectangle should have no affect on the total percent covered because that area is already covered by the yellow and green rectangles.
OK I think I found a solution using a Region that seems to be working for both of my example images above:
Private Function TotalCoveredAreaPercent(ByVal oRectToCheck As RectangleF, ByVal oOverlappingRects As List(Of RectangleF)) As Double
Dim oRegion As New Region(oRectToCheck)
Dim dTotalVisibleArea As Double = 0
Dim dTotalCoveredArea As Double = 0
'now we need to exclude the intersection of our
'overlapping rectangles with our main rectangle:
For Each oOverlappingRect As RectangleF In oOverlappingRects
oRegion.Exclude(RectangleF.Intersect(oRectToCheck, oOverlappingRect))
Next
'now we have access to the non-overlapping
'rectangles that make up the visible area of our main rectangle:
Dim oVisibleRects As RectangleF()
oVisibleRects = oRegion.GetRegionScans(New Drawing2D.Matrix())
'add the area of the visible rectangles together
'to find the total visible area of our main rectangle:
For Each oVisibleRect As RectangleF In oVisibleRects
dTotalVisibleArea += AreaOf(oVisibleRect)
Next
Dim dPercentVisible As Double = dTotalVisibleArea / AreaOf(oRectToCheck) * 100
'percent covered is 100 - the visible percentage:
Return (100 - dPercentVisible)
End Function
This seems to be working pretty well, and is quite simple.
Here is my algorithm. The key point is that we are subtracting out overlaps of overlaps.
Dim baseRect As New RectangleF(10, 10, 20, 20)
Dim otherRectList As New List(Of RectangleF)
otherRectList.Add(New RectangleF(5, 5, 10, 10))
otherRectList.Add(New RectangleF(20, 20, 10, 10))
otherRectList.Add(New RectangleF(10, 5, 10, 10))
Dim overlapRectList As New List(Of RectangleF)
For Each otherRect As RectangleF In otherRectList
If RectangleF.Intersect(otherRect, baseRect) <> RectangleF.Empty Then
overlapRectList.Add(RectangleF.Intersect(otherRect, baseRect))
End If
Next
Dim totalArea As Single = 0
For Each overlapRect As RectangleF In overlapRectList
totalArea += overlapRect.Width * overlapRect.Height
Next
'Subtract out any overlaps that overlap each other
For i = 0 To overlapRectList.Count - 2
For j = i+1 To overlapRectList.Count - 1
If i <> j Then
If RectangleF.Intersect(overlapRectList(i), overlapRectList(j)) <> RectangleF.Empty Then
Dim dupeRect As RectangleF = RectangleF.Intersect(overlapRectList(i), overlapRectList(j))
totalArea -= dupeRect.Width * dupeRect.Height
End If
End If
Next
Next
I amended the code to take into account tcarvin's note. However, I have not plotted out the results on graph paper to see if this is fully correct. I will look at it as soon as I have additional time. Also note that I have not included any code to handle a situation with less than 2 intersections.