Home
Search
 
What's New
Index
Books
Links
Q & A
Newsletter
Banners
 
Feedback
Tip Jar
 
C# Helper...
 
XML RSS Feed
Follow VBHelper on Twitter
 
 
MSDN Visual Basic Community
 
 
 
 
 
TitleDraw contour plots (level curves) for a function with known derivatives
Keywordscontour, level curve, plot
CategoriesGraphics
 

For each contour value:

  • Start at a probe point. Follow the gradient until you find a point on the contour.
  • Move perpendicular to the gradient to find the next probe point. Follow the gradient to find the next point on the contour.
  • Repeat until the curve leaves the area of interest or the curve connects with itself.

This program has several shortcomings. Let me know if you get simple solutions for these.

  • It can get stuck if it reaches a point with zero gradient (a saddle or local extreme). The program could use a nearby random point to get unstuck. These points often have more than one curve passing through them so it may be better to pick multiple probe points rather than to pick one at random.
  • It does not find all contours with the same value if there is more than one. The program must give it different initial probe points so it finds them all. The program could search the area. For example, search every 0.1 units in the X and Y directions. It would need a method for telling when it found a curve it had already found. Perhaps an array indicating that the square (X, Y) already had a curve of the target value in it.
  • It does not avoid problem areas. For example, it may try to evaluate X / Y where Y = 0.
  • It does not follow a contour that leaves the area of interest in both directions. For example, if a curve starts at (1, 1) and moves to the left out of the area, the program should start again at (1, 1) and follow the curve to the right. This would be easy to do.
 
' Return F(X, Y).
Private Function F(ByVal X As Single, ByVal Y As Single) As _
    Single
    F = X * X * X * X - 2 * X * X + Y * Y
End Function

' Return the partial derivative of dF/dX.
Private Function dFdX(ByVal X As Single, ByVal Y As Single) _
    As Single
    dFdX = 4 * X * X * X - 4 * X
End Function

' Return the partial derivative of dF/dY.
Private Function dFdY(ByVal X As Single, ByVal Y As Single) _
    As Single
    dFdY = 2 * Y
End Function

' Find a point on the curve close to this one.
Private Sub FindPointOnCurve(ByRef X As Single, ByRef Y As _
    Single, ByVal level As Single, Optional ByVal start_x _
    As Single = 0.1, Optional ByVal start_y As Single = _
    0.2, Optional ByVal tolerance As Single = 0.01, _
    Optional ByVal initial_delta As Single = 0.1)
Dim dZ As Single
Dim dist As Single
Dim delta As Single
Dim F_XY As Single
Dim dx As Single
Dim dy As Single
Dim direction As Integer

    ' Start at the starting point.
    X = start_x
    Y = start_y
    delta = initial_delta

    ' Repeat until we have a decent solution.
    Do
        ' See how far off we are.
        F_XY = F(X, Y)
        dZ = level - F_XY
        If Abs(dZ) < tolerance Then Exit Do

        ' See if we are switching directions.
        If Sgn(dZ) <> direction Then
            ' We are switching directions. Decrease delta.
            delta = delta / 2
            direction = Sgn(dZ)
        End If

        ' Get the gradient.
        Gradient X, Y, dx, dy
        If Abs(dx) + Abs(dy) < 0.001 Then Exit Do

        ' Move in the right direction.
        X = X + dx * delta * direction
        Y = Y + dy * delta * direction
'Debug.Print X; Y
    Loop
End Sub

' Return the gradient at this point.
Private Sub Gradient(ByVal X As Single, ByVal Y As Single, _
    ByRef dx As Single, ByRef dy As Single)
Dim dist As Single

    dx = dFdX(X, Y)
    dy = dFdY(X, Y)
    dist = Sqr(dx * dx + dy * dy)
    If Abs(dist) < 0.0001 Then
        dx = 0
        dy = 0
    Else
        dx = dx / dist
        dy = dy / dist
    End If
End Sub

' Plot the level curve F(X, Y) = level.
Private Sub PlotLevelCurve(ByVal pic As PictureBox, ByVal _
    level As Single, ByVal xmin As Single, ByVal xmax As _
    Single, ByVal ymin As Single, ByVal ymax As Single, _
    Optional step_size As Single = 0.1, Optional ByVal _
    start_x As Single = 1#, Optional ByVal start_y As _
    Single = 1#, Optional ByVal tolerance As Single = 0.02)
#Const SHOW_TICS = False

Dim num_points As Integer
Dim X0 As Single
Dim Y0 As Single
Dim X As Single
Dim Y As Single
Dim dx As Single
Dim dy As Single

    ' Find a point (X0, Y0) on the level curve.
    FindPointOnCurve X0, Y0, level, start_x, start_y, _
        tolerance

    ' Start here.
    pic.CurrentX = X0
    pic.CurrentY = Y0
    num_points = 1

    ' Start following the level curve.
    X = X0
    Y = Y0
    Do
        ' Find the next point along the curve.
        Gradient X, Y, dx, dy
        If Abs(dx) + Abs(dy) < 0.001 Then Exit Do
        X = X + dy * step_size
        Y = Y - dx * step_size
        FindPointOnCurve X, Y, level, X, Y, tolerance

        ' Draw to this point.
        pic.Line -(X, Y)
        #If SHOW_TICS Then
            pic.Line -Step(dx * 0.1, dy * 0.1)
            pic.Line -Step(-dx * 0.1, -dy * 0.1)
        #End If
        num_points = num_points + 1

        ' See if the point is outside the drawing area.
        If X < xmin Or X > xmax Or _
           Y < ymin Or Y > ymax _
                Then Exit Do

        ' If we have gone at least 4 points, see if this
        ' is where we started.
        If num_points >= 4 Then
            If Sqr((X0 - X) * (X0 - X) + (Y0 - Y) * (Y0 - _
                Y)) <= step_size * 1.1 Then
                pic.Line -(X0, Y0)
                Exit Do
            End If
        End If
    Loop
End Sub
 
For more information on graphics programming in Visual Basic, see my book Visual Basic Graphics Programming.
 
 
Copyright © 1997-2010 Rocky Mountain Computer Consulting, Inc.   All rights reserved.
  Updated