Good day all, I am importing a series of X, Y coordinates, with an "R" for radius, and attempting to draw circles in a picturebox, using number like the ones below;
I'm totally lost on this one...
The easiest way to display graphics in a VB.Net Winforms project is to place the code
that does the drawing inside your into the control's 'Paint' event then inform
Windows that the control is dirty. Windows responds by doing whatever it takes to redraw the control.
This is true for most controls and forms.
While it is the most efficient method for Windows I find it counter-intuitive,
but that is the way it works.
Drawing Circles is also IMHO not as straight forward as one would hope as
the drawing tool requries the boundary rectangle of the circle, not the center pont and radius.
We will get around that by creating a translator function to do the job.
So...
Step 1) Besides importing the 'System.Drawing' namespace you are going to need the 'System .IO' namespace if your data is in a text file.
Code:
Imports System
Imports System.Drawing
Imports System.IO
Public Class Form1
'...
End Class
Step 2) You are also going to need some sort of numerical structure to hold each circle
You could do it with a 2D array, but let's keep more current and use a list of a class.
This also allows us to add other circle properties later like color, line style or visibility.
Code:
Public Class Circle2D
' Holds components that define a circle.
Public Property Pt as PointF = Nothing
Public Property Radius as Single = Nothing
Public ReadOnly Property Rect as RectangleF
Dim Lt as single = Pt.X - Radius
Dim Tp as single = Pt.Y - Radius
Dim Wt as single = Radius * 2
Dim Ht as single = Radius * 2
Return new RectangleF(Lt,Tp,Wt,HT)
End Property
Public Sub New(Byval X as single, Byval Y as single, Byval R as single)
' Constructor method
Pt = new PointF(X,Y)
Radius = R
End Sub
End Class
Step 3) A parser to convert your lines of text into Circle objects and a list variable to hold
your circles and finally a form level variable that tells your paint routine to display the list.
Code:
Imports System
Imports System.Drawing
Imports System.IO
Public Class Form1
Dim Circles as New list(of Circle2D)
Dim UpdatePic as boolean = false
Private Function TextToCircle(Byval Txt as string) as Shape_Circle
Dim Segments() as string = Txt.Trim.Split(" "c)
Dim X as single = Segments(0).Trim.SubString(1) 'Crop 'X' from string
Dim Y as single = Segments(1).Trim.SubString(1) 'Crop 'Y' from string
Dim R as single = Segments(2).Trim.SubString(1) 'Crop 'R' from string
Dim Circ as Circle2D = New Circle2D(X,Y,R)
End Function
' Read text file, Translate, and Fill list
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim sLines() as string = File.ReadAllLines(<FilePath and Name>)
For each sLine as string in sLines
If sline.Startswith("X") then
Circles.Add(TextToCircle(sLine))
End if
Next sLine
UpdatePic = True
Picturebox1.Invalidate '<-- Tell Windows to redraw the picturebox.
End Sub
End Class
Step 4) Write Code for your paint event
Code:
'...
Public Class Form1
'...
Private Sub DrawCircles(ByRef g as Graphics)
with g
For each C as Circle2D in Circles
.DrawEllipse(Pen.Black,C.Rect)
Next
End with
End Sub
Private Sub PictureBox1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
If UpdatePic Then
DrawCircles(e.Graphics)
End If
End Sub
End Class
'...
UP NEXT: Controlling the graphics scale and origin
__________________ Burn the land and boil the sea
You can't take the sky from me
Scaling in Winforms graphics is handled by matrix manipulation in your drawing sub routine.
The drawing matrix object has properties and methods to help you get the desired results.
Code:
With g
' if your graphics represent something in the real world
' then you probably want to ues Inch units.
.PageUnit = GraphicsUnit.Inch
' The matrix defines the coordinate system to use
' in this case 1,0,0,-1 means a standard cartesian coordinates system
' where positive X is to the right and positive Y is Up.
' This differs from standard microsoft windows coordinates where
' positive X is to the Right and positive Y is Down.
' (Add 20 to a button.Top property and the button moves down.)
' The last two arguments may be used for a zoom about center if you want to zoom.
Dim oMatrix As Matrix = New Matrix(1, 0, 0, -1, 0, 0)
' Use the scale method to adjust both x and y scale.
' Use variables if you want to zoom
oMatrix.Scale(0.5,0.5) ' <-- Double Scale I think
' Use the translate method to move the origin
' Use variables to Pan
oMatrix.Translate(o.0, -(0.0))
' We reset the graphics matrix to default settings before we apply
' our new matrix. Remember this whole routne occurs everytime windows
' refreshes the graphics. If you are panning and zooming this is important.
.Transform.Reset()
' Apply your custom matrix
.Transform = oMatrix
' Get rid of jaggy graphics
.SmoothingMode = SmoothingMode.HighQuality
End With
'...
If you want to automatically adust your scale to fix whatever circles may be drawn then
You will need to find the centroid of your circle list data and the delta of it's extents.
Loop through the circle list and using your circle.Rect property find the minimum and maximum x and y.
zoom center origin X = (max_x + min_x) / 2
zoom center origin Y = (max_Y + min_y) / 2
delta_x = max_x - min_x
dekta_y = max_y - min_y
Use whichever delta is larger for the scale.
To keep things simple use a square picturebox.
__________________ Burn the land and boil the sea
You can't take the sky from me
Thanks for your, I'm unable to find much out there on this, and I have never worked with graphics, I played with it, and everything is outside the picture box..
My full code is below, I'm still confused on how to scale everything to fit, and be proportional at the same time,
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Okay, Answer some questions before I waste another four hours of my time.
Do you understand what I mean by a virtual boundary rectangle around your circles?
Imagine you draw 30 random circles on a sheet of paper. Now find the furthest tangent vertical line to the left. Do the same to the right, then top and bottom. This is the exact extents of the area needed to display your circles. The corners are Min and Max x and y.
What you want is the Size of the rectangle. i.e. the delta of the min and max. (max - min).
So now you have a width and height of a virtual rectangle.
But you are not done. What you need to take into account is that your virtual rectangle is almost never square. You have to find out which side is greater and use that to calculate your scale , otherwise your scale will crop off some of the outer geometry.
You have do do the same thing with your picturebox except you want the smallest side. (unless it is square.) Convert its units to inches. Use the
Graphics .DpiX or .DpiY conversion values.
You now have two numbers. virtual rectangle largest side and picturebox smallest side.
Now to fit the virtual rectangle inside the picturebox rectangle you will need a scale factor.
Scale can also be thought of as a ratio. n1 / n2.
Which number comes first is important.
To be on the safe side you will want to adjust your scale by 2 to 5 percent just in case your circles abut the picturebox too closely.
do the math and use the result for both arguments in your matrix.scale() method.
(If your scale arguments are different it will distort your geometry. circles will show as ellipses.)
The last thing you need to do is calculate the center of the virtual rectangle.
This time though you want the actual coordinates not a delta.
This number you plug into the last two arguments of your New Matrix statement.
It will center your virtual rectangle in your picture box.
If it the above is not clear do what I did the first time I tried to figure out autoscaling.
Cut out a small and large piece of paper. Draw some circles on the larger.
Walk through this post with those in hand.
Finally. Another good idea is to make a small test app that does not read values from your DXF. Instead draw a circle and a square with known values.
Say Three inches Diameter. Draw them at 0,0. Make sure your picture box is greater than 3 inches in size. Now play with the Matrix values and scales. A scale of 1.0 should display the circle.
__________________ Burn the land and boil the sea
You can't take the sky from me
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET. subscribe