Years ago I was helping a friend to do some land surveying for area and elevation contour lines. At the time my knowledge of programming was limited to some Fortran IV and a little bit of Wang Basic. Optical theodolites were the only ones in existence and desktop computers were just starting to appear, so the mainframes were the only really available options, but you didn't have access to the computer, you would write the program flow diagram, write the code, punch the cards with program and data and give them to an operator.
Our company's computer was at the accounting department and the computer programmer only worked on COBOL, so he was not able to convert my Fortran program and to compile it, so the survey data was processed by hand.
I had always had that on the back of my mind, and even though I have played a bit with assembler, basic and c, I never decided to write that program. I knew the algorithm was easy to implement but, no need for such a program 30 years later...
Lately I have been writing programs on visual basic for my own consumption and decided to develop that little program.
I see other people dividing polygons on triangles and irregular forms on tiny squares. The best resolution that the computer screen has is the DPI (points per linear inch or pixels) and the best accuracy is ˝ of a square pixel. The screen scale is different from computer to computer according to the settings, the CRT focus, and also it doesn’t correspond to real objects scale, but that can be achieved with the proper factor (squared).
My method of getting the area is to move from point to point on a path and use trapezium areas. These areas are the shadow under the line that connects two consecutive points on a Cartesian chart. Note that the computer screen has the “Y” axis inverted. It increases moving down. The result is the same regardless where you have your coordinate axis, or if you project the shadow to the X-axis or the Y-axis.
The formula for the area of a trapezium is:

But I will use all the distances to x=0 and y=0
A= ˝*(Y1+Y2)*(X2-X1) or A= ˝*(X1+X2)*(Y2-Y1)

The resulting area will be positive or negative depending on what direction we chose to advance on the path. We are calculating areas in excess, but when we advance on the other direction to close the area the excess will be neutralized and we will have a positive or negative balance that would be the area of the enclosed shape. An irregular area needs plenty more points in the path to be defined. But the process is the same.
The creation of the path depends on the type of shape.
On my program I click on the picurebox and fill an arraylist and a datagridview when creating the path for a polygon.


Private Sub PictureBox1_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PureBox1.Click
Dim pt As Point
Dim p As String
Dim myBrush As New SolidBrush(Color.Red)
Dim drawFormat As New StringFormat()
Dim drawFont As New Font("Arial", 10, FontStyle.Bold)
drawFormat.FormatFlags = StringFormatFlags.NoFontFallback
Button4.Enabled = True
pt.X = e.X
pt.Y = e.Y
p = "P" & (Count + 1).ToString
DataGridView1.Item(0, Count).Value = e.X
DataGridView1.Item(1, Count).Value = e.Y
ThePts.Add(pt)
myGraphics.DrawString(p, drawFont, myBrush, ThePts(Count).x + 4, ThePts(Count).y, drawFormat)
myGraphics.DrawEllipse(Pens.Red, e.X, e.Y, 3, 3)
Count += 1
End Sub
For the area I need some string and integer conversions to Double.
Private Function Area() Dim Ar As Double = 0 Dim m As Integer For m = 0 To Count - 2 Ar = Ar + (CDbl((myPoints(m).Y) + CDbl(myPoints(m + 1).Y)) * CDbl((myPoints(m + 1).X) - CDbl(myPoints(m).X)) / 2) Next Ar = Ar + ((CDbl(myPoints(0).Y) + CDbl(myPoints(m).Y)) * CDbl((myPoints(0).X) - CDbl(myPoints(m).X)) / 2) Ar = Ar / (myGraphics.DpiX * myGraphics.DpiY) Return Math.Abs(Ar) 'Clockwise/Counterclockwise End Function
For the irregular shape I left-click and drag the mouse to fill an arraylist, clean the duplicated points, and then do some string manipulation.
Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
iniPointX = e.X
inipointY = e.Y
TextBox32.Text = ""
Select Case e.Button
Case MouseButtons.Left
eventString = "L"
Case MouseButtons.Right
eventString = "R"
Case MouseButtons.Middle
eventString = "M"
Case MouseButtons.XButton1
eventString = "X1"
Case MouseButtons.XButton2
eventString = "X2"
Case MouseButtons.None
eventString = Nothing
End Select
End Sub
Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
LocalMousePosition = PictureBox1.PointToClient(Cursor.Position)
Dim myArray As Point() = {New Point(p1, q1), New Point(e.X, e.Y)}
Dim myPath As New GraphicsPath
Label19.Text = "(X=" & LocalMousePosition.X & " " & "Y=" & LocalMousePosition.Y & ")"
If eventString = "L" Then
myPath.StartFigure()
myPath.AddLines(myArray)
myPath.CloseFigure()
myGraphics.DrawPath(Pens.Blue, myPath)
If Not (p1 = e.X And q1 = e.Y) Then 'Weed out consecutive points with same coordinates
TextBox32.Text = TextBox32.Text & LocalMousePosition.X & "," & LocalMousePosition.Y & vbNewLine
End If
T_lines += 1 'Textbox Line #
End If
If eventString = Nothing Then
myPath.Reset()
myGraphics.Flush()
End If
p1 = e.X
q1 = e.Y
End Sub
And use a different algorithm for the path construction.
Private Sub HandMovePoints()
Dim counter As Integer = 2
Dim list As String = Trim(TextBox32.Text)
Dim pts() As String = TextBox32.Text.Split(CChar(vbNewLine)) '(New Char() {" "c})
Dim pts1() As String
Dim Area As Double
Dim ArStruct As New ArrayList
Dim myPath As New GraphicsPath
Dim TransBrush As New SolidBrush(Color.FromArgb(128, 100, 255, 255))
list = ""
Dim word As String
For Each word In pts
If word.Length > 2 Then
list = list & word & vbNewLine
counter += 1
End If
Next
TextBox32.Text = iniPointX.ToString & "," & inipointY.ToString & vbNewLine & list & iniPointX.ToString & "," & inipointY.ToString
pts = Nothing
Label2.Text = "Trace Points:" & (counter.ToString)
pts = TextBox32.Text.Split(CChar(vbNewLine))
Dim px(pts.Count + 1) As Point
For counter = 0 To UBound(pts)
Dim ms As New MyStruct
pts1 = pts(counter).Split(","c)
px(counter).X = CInt(pts1(0))
px(counter).Y = CInt(pts1(1))
ms.L = CDbl(pts1(0))
ms.R = CDbl(pts1(1))
ArStruct.Add(ms)
Next
px(UBound(pts)) = px(0)
myGraphics.FillPolygon(TransBrush, px)
For counter = 0 To ArStruct.Count - 2
Area = Area + (ArStruct(counter).L + ArStruct(counter + 1).L) * (ArStruct(counter + 1).R - ArStruct(counter).R) / 2
Next
Area = Math.Abs(Area)
Label3.Text = "Area= " & (Area / (myGraphics.DpiX * myGraphics.DpiY)).ToString & " In.˛"
End Sub
In both cases the last point is equal to the first one, but the program takes care of that automatically. Please note that the lines on the path should not intersect each other. On mousemove the click point is not detected so it's stored on a pubic variable.
I didn't take care of making the graphics permanent, so the drawing will disappear if the window is covered or a large picture scrolled.
You can play with this program, change the location of the coordinates axis, adapt it to your particular situation and change the way you input data. The results should be similar. On this case my textbox and datagridview are readonly, but that is just because this demo. There is also no error checking.
Area of Polygon.zip (589.5K)
Number of downloads: 546





MultiQuote




|