Results 1 to 7 of 7

Thread: Polygon clipping by a line

  1. #1

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

    Polygon clipping by a line

    (I wonder if this would be more appropriate for the game development codebank or the math forum).

    This is a subroutine for clipping a general (convex or concave) polygon by a (infinite) straight line defined by 2 points.

    The polygon is a closed contour with N vertices, such that points 1 and N are the same. A polygon UDT is used (see code below) which includes the coordinates of the vertices, the number of branches and pointers to the first point of each branch. Initially the polygon is supposed to have a single branch, but as a result of clipping it may be split into a number of individual closed contours.

    The UDT definitions follow below. The subroutine comes next in a separate post as it's too long to fit in one post. Two screen shots show a demo polygon just before and after the clipping operation. A demo project is also included.
    VB Code:
    1. 'Data type for the polygon vertices
    2. Private Type punkt
    3.     X As Single
    4.     Y As Single
    5. End Type
    6. 'Data type for the entire polygon
    7. Private Type Polygon
    8.     vertex() As punkt
    9.     n As Integer        'Total number of vertices (first and last are the same)
    10.     up() As Integer     'Pointers to the vertices where the polygons start:
    11.     'when the polygon is plotted, we must go to them with "pen up"
    12.     nups As Integer     'Number of sub-polygons (branches): initially 1
    13.     'but after the polygon has been clipped, new polygons may be created
    14. End Type
    Attached Images Attached Images   
    Attached Files Attached Files
    Last edited by krtxmrtz; Aug 21st, 2006 at 04:42 AM.
    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)

  2. #2

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

    Polygon clipping by a line (2)

    VB Code:
    1. Private Sub Clip(plgn As Polygon, p() As punkt, lowerhalf As Boolean)
    2. '
    3. '*********************************************************
    4. 'This subroutine takes a general polygon (may be concave)
    5. 'and clips it by a straight line
    6. 'The boolean variable "lowerhalf" selects which half is
    7. 'to be clipped
    8. '
    9. 'The polygon must not intersect itself (the code does not
    10. 'allow for this possibility, though it shouldn't be too
    11. 'difficult to add some checking code to the calling program)
    12. '
    13. 'The algorithm has been developed from that outlined in
    14. 'the book: "Algorithms for Graphics and Image Processing"
    15. 'by Theo Pavlidis (Computer Science Press, 1982)
    16. 'ISBN: 0-914894-65-X
    17. '*********************************************************
    18. '
    19.     Dim A As Single, B As Single, C As Single
    20.     Dim U1 As Single, U2 As Single
    21.     Dim i As Integer, j As Integer, k As Integer
    22.     Dim k0 As Integer, jcumm As Integer
    23.     'Initial value of n (n will vary as the polygon is being clipped)
    24.     Dim nini As Integer
    25.     Dim kold As Integer
    26.     Dim u As Single, v As Single
    27.     Dim xa As Single, ya As Single, wa As Single, cro As Single
    28.     Dim intr As punkt
    29.     Dim auxpol As Polygon
    30.     'Array of pointers to the next vertex of the polygon
    31.     'Initially, nxt(i) = i+1 for all i (except nxt(plgn.n) = 1) but
    32.     'as the clipping operation proceeds it will have to be updated
    33.     Dim nxt() As Integer
    34.     Dim tempo() As Integer
    35.     Dim dumbo As Integer
    36.     Dim thesign As Integer
    37.     Dim dummy() As Single, dumdum As Single
    38.     Dim zeichen As Integer
    39.    
    40.     'Keep a copy of the initial number of vertices
    41.     nini = plgn.n
    42.    
    43.     'Initialize the array nxt
    44.     ReDim nxt(1 To plgn.n)
    45.     For i = 1 To plgn.n
    46.         Select Case i
    47.             Case plgn.n
    48.                 nxt(i) = 1
    49.             Case Else
    50.                 nxt(i) = i + 1
    51.         End Select
    52.     Next
    53.  
    54.     'Straight line equation:
    55.     'Ax + By + C = 0
    56.     'Calculate the parameters A, B and C from the
    57.     'coordinates of both ends of the line segment
    58.     If p(1).X = p(2).X Then
    59.         'Vertical line
    60.         A = 1
    61.         B = 0
    62.         C = -p(1).X
    63.     Else
    64.         'Any other slope
    65.         A = (p(2).Y - p(1).Y) / (p(2).X - p(1).X)
    66.         B = -1
    67.         C = p(1).Y - A * p(1).X
    68.     End If
    69.    
    70.     'Assign the value of the parameter zeichen
    71.     'according to which of the 2 halves of the
    72.     'the polygon is to be clipped
    73.     If lowerhalf Then
    74.         zeichen = 1
    75.     Else
    76.         zeichen = -1
    77.     End If
    78.     'For the first vertex of the polygon, calculate the quantity U1
    79.     'which represents its position relative to the line:
    80.     'If U1>o the point lies below the line (or at its left side if
    81.     'the line is vertical)
    82.     'If U1 is negative the point is located above it (or to the right)
    83.     U1 = A * plgn.vertex(1).X + B * plgn.vertex(1).Y + C
    84.     If U1 * zeichen <= 0 Then nxt(1) = 0
    85.     'Loop over the other sides of the polygon
    86.     For i = 2 To plgn.n
    87.         'Calculate the position of vertex i
    88.         U2 = A * plgn.vertex(i).X + B * plgn.vertex(i).Y + C
    89.         'Check the position of the previous vertex and of the current vertex
    90.         If U1 * zeichen <= 0 And U2 * zeichen <= 0 Then
    91.             'Set the current vertex pointer to 0 if both vertices
    92.             'are located on the side to be clipped
    93.             nxt(i) = 0
    94.         Else
    95.             'Either the vertices are on the opposite sides or
    96.             'both lie on the side opposite to that to be clipped
    97.             If U1 * zeichen < 0 Or U2 * zeichen < 0 Then
    98.                 'If on opposite sides, calculate the coordinates of the
    99.                 'interception between the line and the polygon side from
    100.                 'the previous vertex to the current one
    101.                 u = plgn.vertex(i - 1).X - plgn.vertex(i).X
    102.                 v = plgn.vertex(i - 1).Y - plgn.vertex(i).Y
    103.                 cro = plgn.vertex(i - 1).X * plgn.vertex(i).Y - plgn.vertex(i - 1).Y * plgn.vertex(i).X
    104.                 xa = -(u * C + B * cro)
    105.                 ya = -(v * C - A * cro)
    106.                 wa = v * B + u * A
    107.                 If wa <> 0 Then
    108.                     'Coordinates of the interception
    109.                     intr.X = xa / wa
    110.                     intr.Y = ya / wa
    111.                 Else
    112.                     MsgBox "Error"
    113.                     Exit Sub
    114.                 End If
    115.                 'The interception point is to be counted as a new
    116.                 'point, so increment the total number of points
    117.                 plgn.n = plgn.n + 1
    118.                 ReDim Preserve plgn.vertex(1 To plgn.n)
    119.                 ReDim Preserve nxt(1 To plgn.n)
    120.                 plgn.vertex(plgn.n).X = intr.X
    121.                 plgn.vertex(plgn.n).Y = intr.Y
    122.                 If U1 * zeichen < 0 Then
    123.                     'If the first point is on the side to be clipped
    124.                     '(the second point is on the opposite side) then
    125.                     'set its pointer to point to the second point
    126.                     nxt(plgn.n) = i
    127.                 Else
    128.                     'Otherwise, set the previous point's pointer to point
    129.                     'to the interception point and the second point's
    130.                     'pointer to zero (as it lies on the side to be clipped)
    131.                     nxt(i - 1) = plgn.n
    132.                     nxt(i) = 0
    133.                     nxt(plgn.n) = 0
    134.                 End If
    135.             End If
    136.             'Set the current second vertex as the first
    137.             'for the comparison in the next loop
    138.             U1 = U2
    139.         End If
    140.     Next
    TO BE CONTINUED IN MY NEXT POST
    Last edited by krtxmrtz; Aug 11th, 2006 at 11:47 AM.
    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)

  3. #3

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

    Re: Polygon clipping by a line (3)

    REST OF THE CODE
    VB Code:
    1. 'An array "tempo" is defined with a number of elements
    2.     'equal to the number of added points, which will be used
    3.     'below to rearrange the array "nxt"
    4.     'Here "tempo" is initialized
    5.     ReDim tempo(nini + 1 To plgn.n)
    6.     For i = nini + 1 To plgn.n
    7.         tempo(i) = i
    8.     Next
    9.    
    10.     'Determine the contour orientation through the calculation
    11.     'of the signed area
    12.     'If it's negative, the contoun is clockwise oriented
    13.     'If it's positive, it's counter-clockwise oriented
    14.     thesign = Int(Sgn(SignedPolygonArea(po)))
    15.    
    16.     'Array dummy is a copy of the Y coordinates (or of the
    17.     'X coordinates, if the line is horizontal) of the new
    18.     'added vertices
    19.     'It will be used for the rearrangement of array tempo
    20.     'Because the actual polygon vertices can't be rearranged
    21.     'we need to reaarange a copy of them in order for the
    22.     'sorting algorithm to work properly
    23.     ReDim dummy(nini + 1 To plgn.n)
    24.     For i = nini + 1 To plgn.n
    25.         Select Case A
    26.             Case 0
    27.                 'Horitzontal line: compare the x coordinates
    28.                 dummy(i) = plgn.vertex(i).X
    29.             Case Else
    30.                 'Any other slope: compare the y coordinates
    31.                 dummy(i) = plgn.vertex(i).Y
    32.         End Select
    33.     Next
    34.    
    35.     'Sort array tempo by increasing (or decreasing) values of
    36.     'the y (or x if the line is horizontal) coordinates of the
    37.     'corresponding added polygon vertices
    38.     For i = nini + 1 To plgn.n - 1
    39.         For j = i + 1 To plgn.n
    40.             'Use "thesign" to take into account the contour orientation
    41.             If thesign * dummy(i) > thesign * dummy(j) Then
    42.                 dumbo = tempo(i)
    43.                 tempo(i) = tempo(j)
    44.                 tempo(j) = dumbo
    45.                 dumdum = dummy(i)
    46.                 dummy(i) = dummy(j)
    47.                 dummy(j) = dumdum
    48.             End If
    49.         Next
    50.     Next
    51.  
    52.     'Elements of array nxt are taken in consecutive pairs
    53.     'One (and only one) of each pair will be zero; this one
    54.     'is then set to point to the other element
    55.     'to the new added points by increasing values of y
    56.     '(or of x is the line is horizontal)
    57.     For i = 1 To (plgn.n - nini) \ 2
    58.         j = nini + 2 * i
    59.         If nxt(tempo(j - 1)) = 0 Then
    60.             nxt(tempo(j - 1)) = tempo(j)
    61.         Else
    62.             nxt(tempo(j)) = tempo(j - 1)
    63.         End If
    64.     Next
    65.          
    66.     'Use a new polygon structure to make up the clipped polygon
    67.     'Initialize the number of branches to zero
    68.     plgn.nups = 0
    69.     'Initialize counter for the vertices in a specific branch
    70.     j = 0
    71.     'Initialize counter for the total number of vertices
    72.     jcumm = 0
    73.     'Allow for plgn.n points, the total number
    74.     'of polygon points including the added ones
    75.     ReDim auxpol.vertex(1 To plgn.n)
    76.     For i = 1 To plgn.n
    77.         'Vertices with nxt(i)=0 are located
    78.         'on the side to be clipped and are
    79.         'neglected
    80.         If nxt(i) <> 0 Then
    81.             'Vertex is on the side to be kept
    82.             If j = 0 Then
    83.                 'First point of the current branch
    84.                 'Update the branch counter
    85.                 plgn.nups = plgn.nups + 1
    86.                 'Update the array of pointers to
    87.                 'the first point of each branch
    88.                 ReDim Preserve plgn.up(1 To plgn.nups)
    89.                 'Assign value of pointer
    90.                 plgn.up(plgn.nups) = jcumm + 1
    91.                 'Initialize k to the first
    92.                 'point of the branch
    93.                 k = i
    94.                 'Set k0 to the index of the
    95.                 'first point of the branch
    96.                 k0 = i
    97.             End If
    98.             Do
    99.                 j = j + 1
    100.                 auxpol.vertex(jcumm + j) = plgn.vertex(k)
    101.                 'Save copy of k
    102.                 kold = k
    103.                 'Update index k
    104.                 k = nxt(k)
    105.                 'Make pointer for the current index = zero so
    106.                 'it will be skipped past in the following loops
    107.                 '(kold must be used as k has just been modified)
    108.                 nxt(kold) = 0
    109.                 'Make up the branch by collecting all points
    110.                 'until the first one is reached
    111.             Loop While k <> k0
    112.             'Add one more point to the current branch and make it
    113.             'the same as the first one (i.e. close the contour)
    114.             j = j + 1
    115.             auxpol.vertex(jcumm + j) = plgn.vertex(k0)
    116.             'Increment total point counter
    117.             jcumm = jcumm + j
    118.             'Initialize the number of points for the next branch
    119.             j = 0
    120.         End If
    121.     Next
    122.        
    123.     'Set total number of points
    124.     plgn.n = jcumm
    125.     'And re-build the polygon after clipping
    126.     ReDim plgn.vertex(1 To plgn.n)
    127.     For i = 1 To plgn.n
    128.         plgn.vertex(i) = auxpol.vertex(i)
    129.     Next
    130.     'Free some memory
    131.     Erase auxpol.vertex
    132.    
    133. End Sub
    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)

  4. #4

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

    Re: Polygon clipping by a line (4)

    Finally, here's this function for calculationg the area of the polygon, called from the above clipping routine:
    VB Code:
    1. Private Function SignedPolygonArea(pol As Polygon) As Single
    2. '
    3. '*********************************************
    4. 'This function has been taken from
    5. 'http://vb-helper.com/howto_polygon_area.html
    6. 'and has been only slightly modified to allow
    7. 'for the "polygon" data type
    8. '
    9. 'In the current project it is used ONLY to
    10. 'determine the orientation (CW or CCW) of
    11. 'the only branch of the original polygon
    12. '*********************************************
    13. '
    14. ' Return the polygon's area in "square" pixels.
    15. ' Add the areas of the trapezoids defined by the
    16. ' polygon's edges dropped to the X-axis. When the
    17. ' program considers a bottom edge of a polygon, the
    18. ' calculation gives a negative area so the space
    19. ' between the polygon and the axis is subtracted,
    20. ' leaving the polygon's area. This method gives odd
    21. ' results for non-simple polygons.
    22. '
    23. ' The value will be negative if the polyogn is
    24. ' oriented clockwise.
    25.     Dim vk As Integer
    26.     Dim area As Single
    27.     ' Get the areas.
    28.     For vk = 1 To pol.n - 1
    29.         area = area + _
    30.             (pol.vertex(vk + 1).X - pol.vertex(vk).X) * _
    31.             (pol.vertex(vk + 1).Y + pol.vertex(vk).Y) / 2
    32.     Next
    33.     ' Return the result.
    34.     SignedPolygonArea = area
    35. End Function
    Last edited by krtxmrtz; Aug 11th, 2006 at 11:48 AM.
    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)

  5. #5
    New Member
    Join Date
    Dec 2012
    Posts
    1

    Re: Polygon clipping by a line

    This code is awesome. I am wondering do you have C# code for this or could you tell me the name of the algorithm.
    It is hard for me to find the book you mentioned in the code.
    Thanks

  6. #6
    PowerPoster Nightwalker83's Avatar
    Join Date
    Dec 2001
    Location
    Adelaide, Australia
    Posts
    13,344

    Re: Polygon clipping by a line

    Quote Originally Posted by shayu View Post
    This code is awesome. I am wondering do you have C# code for this or could you tell me the name of the algorithm.
    It is hard for me to find the book you mentioned in the code.
    Thanks
    You might find either a C# example that does the same thing by searching thee forums or posting in the C# forum asking for either someone to convert the above code or for a C# example of the above.
    when you quote a post could you please do it via the "Reply With Quote" button or if it multiple post click the "''+" button then "Reply With Quote" button.
    If this thread is finished with please mark it "Resolved" by selecting "Mark thread resolved" from the "Thread tools" drop-down menu.
    https://get.cryptobrowser.site/30/4111672

  7. #7

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

    Re: Polygon clipping by a line

    Quote Originally Posted by shayu View Post
    This code is awesome. I am wondering do you have C# code for this or could you tell me the name of the algorithm.
    It is hard for me to find the book you mentioned in the code.
    Thanks
    Sorry, after all this time I just don't remember if I used some published algorithm or I thought up my own method. I'm no longer interested in line clipping, I'm more interested in polygon clipping by a polygon, of which line clipping is a special case.
    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