Option Strict Off
Option Explicit On
Imports System.Linq
Imports System.Collections.Generic
Namespace Waves
   Public Class ObjGrid3D
   Private xmin As Single = 0.0F      ' Min X and Y values.
   Private Zmin As Single = 0.0F
   Private dx As Single = 0.0F        ' Spacing between rows of data.
   Private dz As Single = 0.0F
   Private NumX As Integer = 0        ' Number of X and Y entries.
   Private NumZ As Integer = 0
   Private Points(,) As basWaves.Point3D ' Data values.
   ' Draw a line between the points. Set the max and min values for the line.
   Sub DrawAndSetLine(ByVal canvas As System.Windows.Forms.PictureBox,ByVal x1 As Single,ByVal y1 As Single,ByVal x2 As Single,ByVal y2 As Single,ByVal hi() As Integer,ByVal lo() As Integer)
      Dim tmp As Single = 0.0F
      Dim ix As Integer = 0
      Dim iy As Integer = 0
      Dim y As Single = 0.0F
      Dim dy As Single = 0.0F

      ' Deal only with integers.
      x1 = CInt(x1)
      y1 = CInt(y1)
      x2 = CInt(x2)
      y2 = CInt(y2)

      ' Make x1 < x2.
      If (x2 < x1) Then
         tmp = x1
         x1 = x2
         x2 = tmp
         tmp = y1
         y1 = y2
         y2 = tmp
      End If

      ' Draw the line.
      gmRTL.GUI.ControlHelper.Line(canvas,x1,y1,x2,y2,System.Drawing.ColorTranslator.ToOle(canvas.ForeColor))

      ' Deal with vertical lines separately.
      If (x1 = x2) Then
         If (y1 < y2) Then
            lo(x1) = y1
            hi(x1) = y2
         Else
            lo(x1) = y2
            hi(x1) = y1
         End If
         Exit Sub
      End If

      ' Deal with non-vertical lines.
      dy = CType((y2 - y1) / CInt(x2 - x1),Single)
      y = y1
      For ix = x1 To x2 Step 1
         iy = CInt(y)

         lo(ix) = iy
         hi(ix) = iy

         y = y + dy
      Next
   End Sub
   ' Draw a line between the points using and updating the max and min arrays.
   Sub DrawLine(ByVal canvas As System.Windows.Forms.PictureBox,ByVal x1 As Single,ByVal y1 As Single,ByVal x2 As Single,ByVal y2 As Single,ByVal hi() As Integer,ByVal lo() As Integer)
      Dim tmp As Single = 0.0F
      Dim ix As Integer = 0
      Dim iy As Integer = 0
      Dim y As Single = 0.0F
      Dim dy As Single = 0.0F
      Dim firstx As Integer = 0
      Dim firsty As Integer = 0
      Dim skipping As Boolean = False
      Dim above As Boolean = False

      ' Deal only with integers.
      x1 = CInt(x1)
      y1 = CInt(y1)
      x2 = CInt(x2)
      y2 = CInt(y2)

      ' Make x1 < x2.
      If (x2 < x1) Then
         tmp = x1
         x1 = x2
         x2 = tmp
         tmp = y1
         y1 = y2
         y2 = tmp
      End If

      ' Deal with vertical lines separately.
      If (x1 = x2) Then
         ' Make y1 < y2.
         If (y2 < y1) Then
            tmp = y1
            y1 = y2
            y2 = tmp
         End If
         If (y1 <= lo(x1)) Then
            If (y2 <= lo(x1)) Then
               gmRTL.GUI.ControlHelper.Line(canvas,x1,y1,x2,y2,System.Drawing.ColorTranslator.ToOle(canvas.ForeColor))
            Else
               gmRTL.GUI.ControlHelper.Line(canvas,x1,y1,x2,lo(x2),System.Drawing.ColorTranslator.ToOle(canvas.ForeColor))
            End If
            lo(x1) = y1
         End If
         If (y2 >= hi(x2)) Then
            If (y1 >= hi(x2)) Then
               gmRTL.GUI.ControlHelper.Line(canvas,x1,y1,x2,y2,System.Drawing.ColorTranslator.ToOle(canvas.ForeColor))
            Else
               gmRTL.GUI.ControlHelper.Line(canvas,x1,hi(x1),x2,y2,System.Drawing.ColorTranslator.ToOle(canvas.ForeColor))
            End If
            hi(x2) = y2
         End If
         Exit Sub
      End If

      ' Deal with non-vertical lines.
      dy = CType((y2 - y1) / CInt(x2 - x1),Single)
      y = y1

      ' Find the first visible point.
      skipping = True
      For ix = x1 To x2 Step 1
         iy = CInt(y)
         ' See if this point is visible.
         If (iy <= lo(ix)) Then
            If (skipping) Then
               ' Start a new line below.
               skipping = False
               above = False
               firstx = ix
               firsty = lo(ix)
            End If
         ElseIf (iy >= hi(ix)) Then
            If (skipping) Then
               ' Start a new line above.
               skipping = False
               above = True
               firstx = ix
               firsty = hi(ix)
            End If
         Else
            ' This point is not visible.
            If (Not skipping) Then
               ' Draw the previous visible line.
               If (above) Then
                  ' The line is coming from
                  ' above. Connect it to hi(ix).
                  gmRTL.GUI.ControlHelper.Line(canvas,firstx,firsty,ix,hi(ix),System.Drawing.ColorTranslator.ToOle(canvas.ForeColor))
               Else
                  ' The line is coming from
                  ' below. Connect it to lo(ix).
                  gmRTL.GUI.ControlHelper.Line(canvas,firstx,firsty,ix,lo(ix),System.Drawing.ColorTranslator.ToOle(canvas.ForeColor))
               End If

               skipping = True
            End If
         End If

         If (iy < lo(ix)) Then
            lo(ix) = iy
         End If
         If (iy > hi(ix)) Then
            hi(ix) = iy
         End If

         y = y + dy
      Next

      ' Draw to the last point if necessary.
      If (Not skipping) Then
         gmRTL.GUI.ControlHelper.Line(canvas,firstx,firsty,x2,y2,System.Drawing.ColorTranslator.ToOle(canvas.ForeColor))
      End If
   End Sub
   ' Create the Points array.
   Sub SetBounds(ByVal x1 As Single,ByVal deltax As Single,ByVal xnum As Integer,ByVal z1 As Single,ByVal deltaz As Single,ByVal znum As Integer)
      Dim i As Integer = 0
      Dim j As Integer = 0
      Dim x As Single = 0.0F
      Dim z As Single = 0.0F

      xmin = x1
      Zmin = z1
      dx = deltax
      dz = deltaz
      NumX = xnum
      NumZ = znum
      ReDim Points(NumX,NumZ)

      x = xmin
      For i = 1 To NumX Step 1
         z = Zmin
         For j = 1 To NumZ Step 1
            Points(i,j) = basWaves.init_Point3D()
            Points(i,j).coord(1) = x
            Points(i,j).coord(2) = 0
            Points(i,j).coord(3) = z
            Points(i,j).coord(4) = 1#
            z = z + dz
         Next
         x = x + dx
      Next
   End Sub
   ' Save the indicated data value.
   Sub SetValue(ByVal x As Single,ByVal y As Single,ByVal z As Single)
      Dim i As Integer = 0
      Dim j As Integer = 0

      i = (x - xmin) / dx + 1
      j = (z - Zmin) / dz + 1
      Points(i,j).coord(2) = y
   End Sub
   ' Return a string indicating the object type.
   Public ReadOnly Property ObjectType() As String
      Get
         ObjectType = "GRID"
      End Get
   End Property
   ' Apply a transformation matrix which may not
   ' contain 0, 0, 0, 1 in the last column to the
   ' object.
   Public Sub ApplyFull(ByVal M(,) As Single)
      Dim i As Integer = 0
      Dim j As Integer = 0

      For i = 1 To NumX Step 1
         For j = 1 To NumZ Step 1
            basWaves.m3ApplyFull(Points(i,j).coord,M,Points(i,j).trans)
         Next
      Next
   End Sub
   ' Apply a transformation matrix to the object.
   Public Sub Apply(ByVal M(,) As Single)
      Dim i As Integer = 0
      Dim j As Integer = 0

      For i = 1 To NumX Step 1
         For j = 1 To NumZ Step 1
            basWaves.m3Apply(Points(i,j).coord,M,Points(i,j).trans)
         Next
      Next
   End Sub
   ' Draw the grid without hidden surfaces using the hi-lo algorithm
   Public Sub DrawWithoutHidden(ByVal canvas As System.Windows.Forms.PictureBox,Optional ByVal r As Object = Nothing)
      Dim xmin As Integer = 0
      Dim xmax As Integer = 0
      Dim lo As Integer() = Array.Empty(Of Integer)()
      Dim hi As Integer() = Array.Empty(Of Integer)()
      Dim ix As Integer = 0
      Dim i As Integer = 0
      Dim j As Integer = 0

      ' Bound the X values.
      xmin = Points(1,1).trans(1)
      xmax = xmin
      For i = 1 To NumX Step 1
         For j = 1 To NumZ Step 1
            ix = CInt(Points(i,j).trans(1))
            If (xmin > ix) Then
               xmin = ix
            End If
            If (xmax < ix) Then
               xmax = ix
            End If
         Next
      Next

      ' Create the max and min arrays.
      ReDim lo(xmax)
      ReDim hi(xmax)

      ' Draw the X and Z front edges.
      For i = 2 To NumX Step 1
         ' Draw the edge between
         ' Points(i - 1, NumZ) and Points(i, NumZ)
         ' and set max and min for its values.
         DrawAndSetLine(canvas,Points(i - 1,NumZ).trans(1),Points(i - 1,NumZ).trans(2),Points(i,NumZ).trans(1),Points(i,NumZ).trans(2),hi,lo)
      Next
      For i = 2 To NumZ Step 1
         ' Draw the edge between
         ' Points(NumX, i - 1) and Points(NumX, i)
         ' and set max and min for its values.
         DrawAndSetLine(canvas,Points(NumX,i - 1).trans(1),Points(NumX,i - 1).trans(2),Points(NumX,i).trans(1),Points(NumX,i).trans(2),hi,lo)
      Next


      For i = NumX - 1 To 1 Step -1
         For j = NumZ - 1 To 1 Step -1

            ' This only happens with perspective projection.

            If (Points(i + 1,j).trans(1) >= Points(i,j).trans(1)) Then
               DrawLine(canvas,Points(i,j).trans(1),Points(i,j).trans(2),Points(i,j + 1).trans(1),Points(i,j + 1).trans(2),hi,lo)
               DrawLine(canvas,Points(i,j).trans(1),Points(i,j).trans(2),Points(i + 1,j).trans(1),Points(i + 1,j).trans(2),hi,lo)
            Else
               DrawLine(canvas,Points(i,j).trans(1),Points(i,j).trans(2),Points(i + 1,j).trans(1),Points(i + 1,j).trans(2),hi,lo)
               DrawLine(canvas,Points(i,j).trans(1),Points(i,j).trans(2),Points(i,j + 1).trans(1),Points(i,j + 1).trans(2),hi,lo)
            End If
         Next
      Next
   End Sub
   ' Draw the transformed points on the PictureBox.
   Public Sub Draw(ByVal canvas As System.Windows.Forms.PictureBox,Optional ByVal r As Object = Nothing)
      DrawWithoutHidden(canvas,r)
   End Sub
   End Class
End Namespace
