Results 1 to 6 of 6

Thread: VB Snippet - Math - Shade a closed contour with parallel lines

  1. #1

    Thread Starter
    vbuggy krtxmrtz's Avatar
    Join Date
    May 2002
    Location
    In a probability cloud
    Posts
    5,573

    VB Snippet - Math - Shade a closed contour with parallel lines

    Here are 2 functions (and a demo project):

    InOrOut: a function that checks the position of a point relative to a closed contour (i.e. whether it lies inside, outside or on the border)
    ContourShade: a subroutine that fills a contour (may be irregular) with parallel lines at an angle and separation given as parameters. It issues a call to InOrOut

    I apologize because this is the translation into vb of some code I had written in Fortran a few years ago so, the style may look somewhat messy with all those go to's. But it works!

    VB Code:
    1. Public Function InOrOut(p, q, k, p0, q0)
    2. 'Function to determine the position of point (p0,q0) relative
    3. 'to the closed contour defined by the n points with
    4. 'coordinates p(i), q(i), i=1, 2, ..., k
    5. 'Point 1 must be the same as point k
    6. 'Function values():
    7. '       1: point lies inside the contour
    8. '       -1: point is outside the contour
    9. '       0: point is on the contour border
    10. '*********************************************************************
    11.     Dim kross As Integer, i As Integer
    12.     Dim pp As Single
    13.     'Function initialization
    14.     InOrOut = 0
    15.     'Initialization of kross, a variable which keeps track
    16.     'of how many times the horizontal semi-infinite straight
    17.     'line starting at (p0,q0) and in the positive (right hand side)
    18.     'x axis direction intercepts the contour
    19.     '(The contour may have vertices with angles larger than 180 degrees)
    20.     kross = 0
    21.     'Loop over all contour sides
    22.     For i = 1 To k - 1
    23.         'If the side between the i and i+1 vertices lies entirely
    24.         'above or below the point (p0,q0), then continue on
    25.         'with the next side (there is no intercept)
    26.         If (q(i) > q0 And q(i + 1) > q0) Or (q(i) < q0 And q(i + 1) < q0) Then GoTo NextItem
    27.         'If the side is horizontal avoid the calculation of the intercept by interpolation
    28.         'as there would be a division by zero
    29.         If q(i) = q(i + 1) Then
    30.             'It has to be determined if the point (p0,q0) lies on this horizontal segment
    31.             If (p(i) > p0 And p(i + 1) > p0) Or (p(i) < p0 And p(i + 1) < p0) Then GoTo NextItem
    32.             'If it doesn't, we're done!
    33.             Exit Function
    34.         End If
    35.         'Calculation of pp, the coordinate of the point where the segment connecting the
    36.         'sides i and i+1 and the horizontal straight line that goes through (p0,q0) intercept
    37.         pp = p(i) + (q0 - q(i)) * ((p(i + 1) - p(i)) / (q(i + 1) - q(i)))
    38.         'The sign of pp-p0 determines the position of the intercept relative to (p0,q0)
    39.         If pp - p0 > 0 Then
    40.             'Intercept to the right: increment counter
    41.             kross = kross + 1
    42.         ElseIf pp - p0 = 0 Then
    43.             Exit Function
    44.         End If
    45.         'If the intercept lies to the left, take no action and continue on
    46. NextItem:
    47.     Next
    48.     'End of loop, reinitialization of InOrOut
    49.     InOrOut = 1
    50.     'If the number of intercepts is even the point (p0,q0) lies out of the contour
    51.     If kross Mod 2 = 0 Then InOrOut = -1
    52. End Function
    53.  
    54. '*************************************************
    55. '*************************************************
    56.  
    57. Public Sub ContourShade(X, Y, xc, n, sep, angle)
    58. 'It fills a closed contour defined by n points with coordinates
    59. 'x(i), y(i), i=1, 2, ..., n
    60. 'Points #1 and #n are the same, i.e. x(1)=x(n) & y(1)=y(n)
    61. 'xc is a workspace
    62. 'sep is the separation between the parallel shading lines
    63. 'angle is the angle in degrees between the lines and the x axis (horizontal)
    64. '************************************************************************************
    65.     Const Pi = 3.141592654
    66.     Dim radians As Single
    67.     Dim yLow As Single, yHigh As Single
    68.     Dim dummyX As Single, dummyY As Single
    69.     Dim x1 As Single, y1 As Single
    70.     Dim Small As Single, Large As Single
    71.     Dim v1 As Single, w1 As Single, v2 As Single, w2 As Single
    72.     Dim i As Integer, ii As Integer, j As Integer, nc As Integer
    73.     'Convert angle to radians
    74.     radians = angle * Pi / 180
    75.     'Rotate contour by angle -angle so that we will deal with horizontal parallel
    76.     'lines, much easier to handle
    77.     For i = 1 To n
    78.         dummyX = X(i)
    79.         dummyY = Y(i)
    80.         X(i) = dummyX * Cos(radians) + dummyY * Sin(radians)
    81.         Y(i) = -dummyX * Sin(radians) + dummyY * Cos(radians)
    82.     Next
    83.     'Now find the minimum and maximum y values
    84.     yLow = Y(1)
    85.     yHigh = Y(1)
    86.     For i = 2 To n - 1
    87.         If Y(i) < yLow Then yLow = Y(i)
    88.         If Y(i) > yHigh Then yHigh = Y(i)
    89.     Next
    90.     'Initialize y1, the vertical coordinate of the line to be drawn
    91.     y1 = yLow + sep
    92.     'Loop over the lines
    93. NextLine:
    94.     'Initialize nc, the number of points where the line intercepts the contour
    95.     nc = 0
    96.     'Loop over the contour vertices. For each one of them, may or may not cross it.
    97.     'If it does, the point where this occurs is stored in the workspace xc and nc is incremented
    98.     For i = 1 To n - 1
    99.         'Skip horizontal sides
    100.         If Y(i) = Y(i + 1) Then GoTo NextItem
    101.         'Calculate x1, the horizontal coordinate where the line intercepts the contour
    102.         'side being considered
    103.         x1 = X(i) + (y1 - Y(i)) * (X(i + 1) - X(i)) / (Y(i + 1) - Y(i))
    104.         'Calculate xLarge and xSmall, the larger and smaller of the pair x(i) & x(i+1)
    105.         If X(i) < X(i + 1) Then
    106.             Small = X(i)
    107.             Large = X(i + 1)
    108.         Else
    109.             Small = X(i + 1)
    110.             Large = X(i)
    111.         End If
    112.         'Handle the vertical sides as a special case
    113.         If X(i) = X(i + 1) Then
    114.             'First calculate which of y(i) and y(i+1) is the larger and the smaller
    115.             If Y(i) < Y(i + 1) Then
    116.                 Small = Y(i)
    117.                 Large = Y(i + 1)
    118.             Else
    119.                 Small = Y(i + 1)
    120.                 Large = Y(i)
    121.             End If
    122.             'If the intercept point lies out of the side, go for the next side
    123.             If Small > x1 Or Large < x1 Then GoTo NextItem
    124.             'If it lies completely within the side, count it in as a real intercept
    125.             'point and store it
    126.             If (x1 <> X(i) Or y1 <> Y(i)) And (x1 <> X(i + 1) Or y1 <> Y(i + 1)) Then GoTo Increment
    127.         Else
    128.             'If the intercept lies out of the side, go to the next one
    129.             If Small > x1 Or Large < x1 Then GoTo NextItem
    130.             'If it lies completely within the side, count it really as an intercept and store it
    131.             If (x1 <> X(i) Or y1 <> Y(i)) And (x1 <> X(i + 1) Or y1 <> Y(i + 1)) Then GoTo Increment
    132.             'If it coincides with one of the vertices go to take special action
    133.         End If
    134.         'Now for the special action: we want to check whether both sides
    135.         '(i, i+1) and (i+1, i+2) are above or below the horizontal line
    136.         'at the same time
    137.         ii = i + 2
    138.         'Avoid having it out of range when i=n-1
    139.         If i = n - 1 Then ii = 2
    140.         'If on the same side then it is not an intercept
    141.         If (Y(i) - y1) * (Y(ii) - y1) >= 0 Then GoTo NextItem
    142.         'Increment the intercept counter
    143. Increment:
    144.         nc = nc + 1
    145.         'Store the intercept x coordinate
    146.         xc(nc) = x1
    147. NextItem:
    148.     Next
    149.     'Arrange the xc from samller to larger
    150.     For i = 1 To nc - 1
    151.         ii = i
    152.         For j = i + 1 To nc
    153.             If xc(ii) > xc(j) Then ii = j
    154.         Next
    155.         dummyX = xc(ii)
    156.         xc(ii) = xc(i)
    157.         xc(i) = dummyX
    158.     Next
    159.     'Loop over the intercepts
    160.     'Handle them in couples
    161.     For i = 1 To nc - 1
    162.         'dummyX is the coordinate of a point lying midway
    163.         'between x(i) and x(i+1)
    164.         dummyX = 0.5 * (xc(i) + xc(i + 1))
    165.         'Call a function to determine whether this point (dummyX,y1)
    166.         'lies inside the contour
    167.         'If it does, plot the line. If it doesn't, check the next couple
    168.         If InOrOut(X, Y, n, dummyX, y1) = 1 Then
    169.             'Rotate back the 2 adjacent points to the original angle
    170.             v1 = xc(i) * Cos(radians) - y1 * Sin(radians)
    171.             w1 = xc(i) * Sin(radians) + y1 * Cos(radians)
    172.             v2 = xc(i + 1) * Cos(radians) - y1 * Sin(radians)
    173.             w2 = xc(i + 1) * Sin(radians) + y1 * Cos(radians)
    174.             'And finally plot a line connecting them!
    175.             Picture1.Line (v1, w1)-(v2, w2)
    176.         End If
    177.     Next
    178.     'Now go for the next horizontal line
    179.     y1 = y1 + sep
    180.     'If we haven't yet reached the top go back to start with the next line
    181.     If y1 < yHigh Then GoTo NextLine
    182.     'Else, rotate back the contour
    183.     For i = 1 To n
    184.         dummyX = X(i)
    185.         dummyY = Y(i)
    186.         X(i) = dummyX * Cos(radians) - dummyY * Sin(radians)
    187.         Y(i) = dummyX * Sin(radians) + dummyY * Cos(radians)
    188.     Next
    189.     'That's all folks!
    190. End Sub
    Attached Files Attached Files
    Last edited by krtxmrtz; Mar 14th, 2003 at 04:52 AM.

  2. #2

    Thread Starter
    vbuggy krtxmrtz's Avatar
    Join Date
    May 2002
    Location
    In a probability cloud
    Posts
    5,573
    An improved version of the demo project (the basic code is the same).
    Attached Files Attached Files

  3. #3

    Thread Starter
    vbuggy krtxmrtz's Avatar
    Join Date
    May 2002
    Location
    In a probability cloud
    Posts
    5,573
    Here's a minor change in the InOrOut function above, the purpose of which is to find out the position of a point relative to a closed contour.

    There is a degenerate case that I had not dealt with: if the point has the same vertical (q) coordinate as one of the vertices of the contour, then the variable "kross" is counted twice. To avoid this I have added an if statement (see changes in bold red below).
    VB Code:
    1. Public Function InOrOut(p, q, k, p0, q0)
    2. 'Function to determine the position of point (p0,q0) relative
    3. 'to the closed contour defined by the n points with
    4. 'coordinates p(i), q(i), i=1, 2, ..., k
    5. 'Point 1 must be the same as point k
    6. 'Function values():
    7. '       1: point lies inside the contour
    8. '       -1: point is outside the contour
    9. '       0: point is on the contour border
    10. '*********************************************************************
    11.     Dim kross As Integer, i As Integer
    12.     Dim pp As Single
    13.     'Function initialization
    14.     InOrOut = 0
    15.     'Initialization of kross, a variable which keeps track
    16.     'of how many times the horizontal semi-infinite straight
    17.     'line starting at (p0,q0) and in the positive (right hand side)
    18.     'x axis direction intercepts the contour
    19.     '(The contour may have vertices with angles larger than 180 degrees)
    20.     kross = 0
    21.     'Loop over all contour sides
    22.     For i = 1 To k - 1
    23.         'If the side between the i and i+1 vertices lies entirely
    24.         'above or below the point (p0,q0), then continue on
    25.         'with the next side (there is no intercept)
    26.         If (q(i) > q0 And q(i + 1) > q0) Or (q(i) < q0 And q(i + 1) < q0) Then GoTo NextItem
    27.         'If the side is horizontal avoid the calculation of the intercept by interpolation
    28.         'as there would be a division by zero
    29.         If q(i) = q(i + 1) Then
    30.             'It has to be determined if the point (p0,q0) lies on this horizontal segment
    31.             If (p(i) > p0 And p(i + 1) > p0) Or (p(i) < p0 And p(i + 1) < p0) Then GoTo NextItem
    32.             'If it doesn't, we're done!
    33.             Exit Function
    34.         End If
    35.         'Calculation of pp, the coordinate of the point where the segment connecting the
    36.         'sides i and i+1 and the horizontal straight line that goes through (p0,q0) intercept
    37.         pp = p(i) + (q0 - q(i)) * ((p(i + 1) - p(i)) / (q(i + 1) - q(i)))
    38.         'The sign of pp-p0 determines the position of the intercept relative to (p0,q0)
    39.         If pp - p0 > 0 Then
    'Intercept to the right: increment counter (but only if the intercept does not lie
    'on the first vertex, to avoid counting the same intercept twice!)
    If q0 <> q(i) Then kross = kross + 1

    VB Code:
    1. ElseIf pp - p0 = 0 Then
    2.             Exit Function
    3.         End If
    4.         'If the intercept lies to the left, take no action and continue on
    5. NextItem:
    6.     Next
    7.     'If the number of intercepts is even, the point (p0,q0) lies out of the contour
    8.     'If it's odd then it lies inside
    9.     If kross Mod 2 = 0 Then
    10.         InOrOut = -1
    11.     Else
    12.         InOrOut = 1
    13.     End If
    14. End Function
    Last edited by krtxmrtz; Jul 8th, 2005 at 02:42 AM.

  4. #4

    Thread Starter
    vbuggy krtxmrtz's Avatar
    Join Date
    May 2002
    Location
    In a probability cloud
    Posts
    5,573
    (Updated demo project)
    Attached Files Attached Files

  5. #5
    New Member
    Join Date
    May 2005
    Posts
    5

    Re: VB Snippet - Math - Shade a closed contour with parallel lines

    i tried out your contourfill. but i hope that you can help me with this. cause the contour that i need to draw out is with 8 points and it will form a circle.

  6. #6

    Thread Starter
    vbuggy krtxmrtz's Avatar
    Join Date
    May 2002
    Location
    In a probability cloud
    Posts
    5,573

    Re: VB Snippet - Math - Shade a closed contour with parallel lines

    Quote Originally Posted by weicheng83
    i tried out your contourfill. but i hope that you can help me with this. cause the contour that i need to draw out is with 8 points and it will form a circle.
    Well, I hoped the demo project was sufficiently explicit, all you have to do is copy the code... In the demo itself you can change the points' coordinates in the Form_Load subroutine and place your eight points. Actually you must add an extra 9th point with the same coordinates as the first, for the purpose of closing the contour.
    Otherwise let me know exactly what your problem is...
    Lottery is a tax on people who are bad at maths
    If only mosquitoes sucked fat instead of blood...
    To do is to be (Descartes). To be is to do (Sartre). To be do be do (Sinatra)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width