-
Aug 12th, 2013, 04:02 PM
#1
Thread Starter
Addicted Member
Basic Graphics Logic Help
Hi,
I have been having a very hard time wrapping my head around drawing in vb.net
Here is what I am doing,
vb.net Code:
Public Class Form1
Dim _Pen As Pen
Dim min As System.Drawing.Point = New Point(521, 211)
Dim max As System.Drawing.Point = New Point(1261, 1249)
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
If max.X = 0 Then
Exit Sub
End If
Dim Img As New Bitmap(max.X, max.Y)
Dim g As Graphics = Graphics.FromImage(Img)
g.Clear(Color.White)
_Pen = New Pen(Brushes.LightBlue, 5)
_Pen.DashStyle = DashStyle.Dash
g.DrawLine(_Pen, min.X, min.Y, max.X, max.Y)
PictureBox1.Image = Img
End Sub
End Class
So I am creating a image that is 1261 x 1249 and then I draw on this image a line from the bottom to the top.
I then set this image to my picture box which has dimensions of 638 x 723. But the line never shows up or shows up at a random place. It is very furstrating lol.
Does my logic make sense?
-
Aug 12th, 2013, 04:25 PM
#2
Re: Basic Graphics Logic Help
I tried your code. here's what it drew:
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Aug 12th, 2013, 04:30 PM
#3
Re: Basic Graphics Logic Help
The reason why it wouldn't show up is because you picturebox isn't big enough. It will appear off the visible portion of your picturebox. If you want to appear properly, then either resize your picturebox or set the SizeMode to AutoSize, StretchImage, or Zoom.
-
Aug 12th, 2013, 04:34 PM
#4
Re: Basic Graphics Logic Help
You code makes sense to me. As far as I can see you are drawing a diagonal dashed light blue line from the top left (min) to the bottom right (max) corner of a rectangle. That should work correctly on the image Img.
But there is one thing that you haven't said: what is the SizeMode setting of the PictureBox? It will determine how the Image Img will be displayed in the PictureBox. You can set the SizeMode in the Designer or in your code.
For example, if you have SizeMode = None, you should be able to see part of your line. That's because the line doesn't start until (521, 211), which is near the right-hand side of the PictureBox. But if you set SizeMode = StretchImage you should be able to see the whole image compressed into the PictureBox. If you don't want to think about the SizeMode, you should start off with the image Img the same size as the PictureBox (to be more accurate, the PictureBox ClientRectangle, which excludes the border, if any).
BB
EDIT: actually dday9 said exactly what I meant in fewer words. I'm always too slow!
Last edited by boops boops; Aug 12th, 2013 at 04:39 PM.
-
Aug 13th, 2013, 12:51 PM
#5
Thread Starter
Addicted Member
Re: Basic Graphics Logic Help
Thanks for the input guys. So If I want that line to run across the form and all of it to be visible?
I would rather not use the SizeMode, as this screws up all the graphic paths I have and makes my objects unclickable :P
Could someone assist me in the logic to convert all the values I have into the picturebox size?
I tried this but it is still a bit off. I am multiplying all of my x and y values by (Height of picturebox/my max Y) and (Wdith of picturebox/my max x)
Code:
Imports System.Drawing.Drawing2D
Public Class Form1
Dim _Pen As Pen
Dim min As System.Drawing.Point = New Point(521, 211)
Dim max As System.Drawing.Point = New Point(1261, 1249)
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
If max.X = 0 Then
Exit Sub
End If
Dim Img As New Bitmap(PictureBox1.Height, PictureBox1.Width)
Dim g As Graphics = Graphics.FromImage(Img)
g.Clear(Color.White)
Dim ratiox As Single = PictureBox1.Width / max.X
Dim ratioy As Single = PictureBox1.Height / max.Y
_Pen = New Pen(Brushes.LightBlue, 5)
_Pen.DashStyle = DashStyle.Dash
g.DrawLine(_Pen, min.X * ratiox, min.Y * ratioy, max.X * ratiox, max.Y * ratioy)
PictureBox1.Image = Img
End Sub
Private Sub PictureBox1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
Label1.Text = "X : " & e.X & " Y : " & e.Y
End Sub
End Class
-
Aug 14th, 2013, 02:49 PM
#6
Re: Basic Graphics Logic Help
To start with, you are not getting the line to fill the picture because you need to translate (shift) the coordinates as well as scale them. For a single line, you could simply set X=0 and Y=0 in Graphics.DrawLine. But if you are drawing more than 1 line or other shapes it would be pointless do that for each one separately. Instead you should transform the Graphics object, which will apply to all the lines etc.
The reason dday and I mentioned SizeMode is because you are doing your drawing to a bitmap, and then using it as the PictureBox Image. That is the "easy" way of using a PictureBox, but it won't help you with hit-testing,. So I suggest you start by doing your graphics the Paint event of the PictureBox, instead of using a separate bitmap. Here's an example:
Code:
Public Class Form1
Private MinX, MinY, MaxX, MaxY As Integer
Private scaleX, scaleY As Single
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
'Calculate the minimum and maximum X and Y values of what you want to draw here.
'For the while, let's just insert your test values.
MinX = 521
MinY = 211
MaxX = 1261
MaxY = 1249
'Calculate the X and Y scaling factors
scaleX = CSng(PictureBox1.ClientSize.Width / (MaxX - MinX))
scaleY = CSng(PictureBox1.ClientSize.Height / (MaxY - MinY))
'Trigger the Paint event with the new data.
PictureBox1.Invalidate()
End Sub
Private Sub PictureBox1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
If scaleX = 0 Then Exit Sub
'Transform the scale and the coordinates.
e.Graphics.ScaleTransform(scaleX, scaleY)
e.Graphics.TranslateTransform(-MinX, -MinY)
'Draw the lines etc.
Using _Pen As New Pen(Color.LightBlue, 5) With {.DashStyle = Drawing2D.DashStyle.Dash}
e.Graphics.DrawLine(_Pen, MinX, MinY, MaxX, MaxY)
End Using
End Sub
End Class
Note that I haven't used Points min and max, because if you have more than one line etc. the minimum and maximum values may not be the same points. It's a bit strange to use different scaling factors for the X and Y directions: normally you would use just one scaling factor. Maybe you have some good reason for doing that, but otherwise you can work out which scaling gives the best fit, the X direction or the Y direction.
BB
Last edited by boops boops; Aug 14th, 2013 at 02:54 PM.
-
Aug 14th, 2013, 03:28 PM
#7
Thread Starter
Addicted Member
Re: Basic Graphics Logic Help
Originally Posted by boops boops
To start with, you are not getting the line to fill the picture because you need to translate (shift) the coordinates as well as scale them. For a single line, you could simply set X=0 and Y=0 in Graphics.DrawLine. But if you are drawing more than 1 line or other shapes it would be pointless do that for each one separately. Instead you should transform the Graphics object, which will apply to all the lines etc.
The reason dday and I mentioned SizeMode is because you are doing your drawing to a bitmap, and then using it as the PictureBox Image. That is the "easy" way of using a PictureBox, but it won't help you with hit-testing,. So I suggest you start by doing your graphics the Paint event of the PictureBox, instead of using a separate bitmap. Here's an example:
Code:
Public Class Form1
Private MinX, MinY, MaxX, MaxY As Integer
Private scaleX, scaleY As Single
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
'Calculate the minimum and maximum X and Y values of what you want to draw here.
'For the while, let's just insert your test values.
MinX = 521
MinY = 211
MaxX = 1261
MaxY = 1249
'Calculate the X and Y scaling factors
scaleX = CSng(PictureBox1.ClientSize.Width / (MaxX - MinX))
scaleY = CSng(PictureBox1.ClientSize.Height / (MaxY - MinY))
'Trigger the Paint event with the new data.
PictureBox1.Invalidate()
End Sub
Private Sub PictureBox1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
If scaleX = 0 Then Exit Sub
'Transform the scale and the coordinates.
e.Graphics.ScaleTransform(scaleX, scaleY)
e.Graphics.TranslateTransform(-MinX, -MinY)
'Draw the lines etc.
Using _Pen As New Pen(Color.LightBlue, 5) With {.DashStyle = Drawing2D.DashStyle.Dash}
e.Graphics.DrawLine(_Pen, MinX, MinY, MaxX, MaxY)
End Using
End Sub
End Class
Note that I haven't used Points min and max, because if you have more than one line etc. the minimum and maximum values may not be the same points. It's a bit strange to use different scaling factors for the X and Y directions: normally you would use just one scaling factor. Maybe you have some good reason for doing that, but otherwise you can work out which scaling gives the best fit, the X direction or the Y direction.
BB
Thank You very much for the explanation.
When I used the transform and translate before my hittest were all wrong, but I guess that was because I was not redrawing the box?
So if I were to add all of my drawings into the paint event, it should work even if I use the zoom sizemode?
Let me explain what I am doing, the project above was just a test project.
My program talks to another 3rd party through the COM interface, which is where I obtain the Mix and Max values. I get these to draw the basic outline of the system.
In the program there are buttons to select specific paths, when a path is selected it is drawn in the picturebox and clicking on the path yields more info.
So in order to get it working correctly now I will have to do the following:
-I will calculate the scales at the beginning when the min and max from the program is obtained.
-Move all of my graphics code into the paint even from the Picturebox and have it transformed to the scale.
I am sorry I havent posted my code, but all of the graphics are mixed with other things that happens when a path is selected. I guess I will have to separate everything now.
Hopefully this works. Thanks again
-
Aug 15th, 2013, 08:09 AM
#8
Thread Starter
Addicted Member
Re: Basic Graphics Logic Help
Almost there.
My lines appear to be upside down and the HIT test dont work :\
Here is the code now
vb.net Code:
Dim _SecondaryPaths As New List(Of System.Drawing.Drawing2D.GraphicsPath) Dim _Paths As New List(Of System.Drawing.Drawing2D.GraphicsPath) Dim namepath As New List(Of NamedPath) Public Sub Draw() scaleX = CSng(PictureBox1.ClientSize.Width / (max.X - min.X)) scaleY = CSng(PictureBox1.ClientSize.Height / (max.Y - min.Y)) PictureBox1.Invalidate() End sub Private Sub PictureBox1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint e.Graphics.ScaleTransform(scaleX, scaleY) e.Graphics.TranslateTransform(-min.X, -min.Y) _Pen = New Pen(Brushes.LightBlue, 5) _Pen.DashStyle = DashStyle.Dash e.Graphics.DrawLine(_Pen, min.X, min.Y, min.X, max.Y) e.Graphics.DrawLine(_Pen, min.X, max.Y, max.X, max.Y) e.Graphics.DrawLine(_Pen, max.X, max.Y, max.X, min.Y) e.Graphics.DrawLine(_Pen, max.X, min.Y, min.X, min.Y) Dim graphiccounter As Integer = 0 _Paths.Clear() namepath.Clear() For Each row As DataGridViewRow In DataGridView2.Rows If row.Visible = True Then _Paths.Add(New GraphicsPath) namepath.Add(New NamedPath) _SecondaryPaths.Add(New GraphicsPath) 'Over here my program talks to other program and gets all the x,y co-ordinates. 'For each path that I get from the other program, they are defined with multiple points 'the number of points is stored in result For k = 1 To result - 1 x_loc(k) = x(k) y_loc(k) = y(k) x_loc(k + 1) = x(k + 1) y_loc(k + 1) = y(k + 1) If drawtype = draw.onlypath Then _Paths(graphiccounter).AddLine(x_loc(k), y_loc(k), x_loc(k + 1), y_loc(k + 1)) namepath(graphiccounter).Name = row.Cells("Id").Value namepath(graphiccounter).Path = _Paths(graphiccounter) 'e.graphics.FillEllipse(Brushes.Black, x_loc(k + 1) - 4, y_loc(k + 1) - 4, 8, 8) ElseIf drawtype = draw.withpath Or drawtype = draw.pathwhenselected Then _SecondaryPaths(graphiccounter).AddLine(x_loc(k), y_loc(k), x_loc(k + 1), y_loc(k + 1)) End If Next 'This draws a transparent line over the paths with a width thicker than the paths. This is what the hit test checks For der = 0 To namepath.Count - 1 _Pen = New Pen(Brushes.Transparent, 20) e.Graphics.DrawPath(_Pen, namepath(der).Path) graphiccounter += 1 Next Protected Sub OnMeouseClick(sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseClick Dim mp As New Point(e.X, e.Y) For k = 0 To namepath.Count - 1 If Me.namepath(k).Path.IsOutlineVisible(mp, _Pen) = False Then Me._MouseIsOnLine = False Else 'I Process what needs to be if the line is clicked Me._MouseIsOnLine = True Exit For End If Next End Sub
EDIT: For some reason, even thought my graphics show up on the sheet, the paths for the hit test show up outside of the picture box
Ok Say I have a path drawn from 200,200 to 1000,1000. When I click these numbers are stored in the paths array so it checks if the point I clicked on in on the given path. BUT because I used
vb.net Code:
e.Graphics.ScaleTransform(scaleX, scaleY) e.Graphics.TranslateTransform(-min.X, -min.Y)
All those points have been changed. I tried taking the point clicked and multiplying it by the scale and add the translate but it still is off :\
Found this but still trying to figure out the the matrix stuff happening in the Paint Function
http://stackoverflow.com/questions/1...nsformed-paths
Last edited by Crzyrio; Aug 15th, 2013 at 09:22 AM.
-
Aug 15th, 2013, 11:16 AM
#9
Thread Starter
Addicted Member
-
Aug 15th, 2013, 11:54 AM
#10
Re: Basic Graphics Logic Help
The Graphics Appear Fine, but when I do
Well, don't do it then!
You're essentially changing the order and/or time at which things are done which can effect things in a surprising (though entirely logical) way. It takes some getting used to.
Butt my Graphics are all still upside down :\
You have remembered that Y co-ordinates increase as you go down not up as in standard graphing so that the top left corner is 0,0?
As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"
Reviews: "dunfiddlin likes his DataTables" - jmcilhinney
Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!
-
Aug 15th, 2013, 11:57 AM
#11
Thread Starter
Addicted Member
Re: Basic Graphics Logic Help
Originally Posted by dunfiddlin
Well, don't do it then!
You're essentially changing the order and/or time at which things are done which can effect things in a surprising (though entirely logical) way. It takes some getting used to.
You have remembered that Y co-ordinates increase as you go down not up as in standard graphing so that the top left corner is 0,0?
But I need to do it in order for the Hittest to work :|
Thanks, I just changed all the values to
Picturebox1.Height - original co-ordinate
Now just working on figuring out why some of the graphics are getting cut off.
-
Aug 15th, 2013, 01:10 PM
#12
Re: Basic Graphics Logic Help
Hi Cryzyrio, life is too short to get involved in the code you posted in #8, but I'd like to offer you a working example of how to do hit testing on GraphicsPaths in a transformed Graphics. To keep things simple I'll adapt the same code as I posted. The main differences are:
1. it uses a path (gPath) with Graphics.DrawPath to draw the line instead of Graphics.DrawLine
2. it uses two matrices, matrix and inverseMatrix. matrix is for transforming the Graphics in the Paint sub. The inverseMatrix is used in the MouseClick sub. It reverses the process, to find where the point actually clicked in the PictureBox is in "world" coordinates (the coordinates of the original data and the GraphicsPaths).
3. it uses GraphicsPath.IsOutlineVisible to perform the hit test. This takes a pen as one of its argumentsl; only purpose is to widen the hit area to make it easier to use. This pen doesn't have to be the same as the one used for drawing
Code:
Public Class Form1
Private MinX, MinY, MaxX, MaxY As Integer
Private scaleX, scaleY As Single
Private gPath As New Drawing2D.GraphicsPath
Private matrix, inverseMatrix As New Drawing2D.Matrix
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
'Calculate the minimum and maximum X and Y values of what you want to draw here.
'For the while, let's just insert your test values.
MinX = 521
MinY = 211
MaxX = 1261
MaxY = 1249
'Create the GraphicsPath
gPath.AddLine(MinX, MinY, MaxX, MaxY)
'Calculate the X and Y scaling factors
scaleX = CSng(PictureBox1.ClientSize.Width / (MaxX - MinX))
scaleY = CSng(PictureBox1.ClientSize.Height / (MaxY - MinY))
'create the matrix
matrix.Scale(scaleX, scaleY)
matrix.Translate(-MinX, -MinY)
'create the inverse matrix
inverseMatrix = matrix.Clone
inverseMatrix.Invert()
'Trigger the Paint event with the new data.
PictureBox1.Invalidate()
End Sub
Private Sub PictureBox1_MouseClick(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseClick
'get the "world" equivalent of the mouse click position
Dim pts() As Point = {e.Location}
inverseMatrix.TransformPoints(pts)
Dim wLocation As Point = pts(0)
'hit test:
Using pn As New Pen(Color.Black, 10)
If gPath.IsOutlineVisible(wLocation, pn) Then
MessageBox.Show("click location = " & e.Location.ToString & vbCrLf & _
"world location = " & wLocation.ToString)
End If
End Using
End Sub
Private Sub PictureBox1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
'Transform the scale and the coordinates.
e.Graphics.Transform = matrix
'Draw the lines etc.
Using _Pen As New Pen(Color.LightBlue, 5) With {.DashStyle = Drawing2D.DashStyle.Dash}
e.Graphics.DrawPath(_Pen, gPath)
End Using
End Sub
End Class
BB
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|