Android Question 3D Tin Model using OpenGL

Terradrones

Active Member
Licensed User
I have a TIN Model consisting of Triangles as defined by their Vertexes. I would like to display this as a 3D Model using OpenGL, but my code is full of errors. If somebody could please give me a push in the right direction. Here is my code:

B4X:
Sub Render3D
    If GlSV.DeviceAPILevel < 8 Then
        MsgboxAsync("OpenGL Is Not Supported On This Device", "OpenGL Error")
        Panels
        Panel1.Visible=True
    End If
    Panels
    Panel6.Visible = True
    Pnl3DView.Visible = True
    ProgressDialogShow("Generating 3D Model...")
    Sleep(0)
    CalculateScalingFactors
    GetVertices

    GlSV.Initialize2(GlSV.RENDERMODE_WHEN_DIRTY, "glsv", 16, 0)
    Pnl3DView.AddView(GlSV, 0, 0, Pnl3DView.Width, Pnl3DView.Height)
    ProgressDialogHide
End Sub

Sub Butt3_Click
'    Timer1.Enabled = False
    Panels
    Panel1.Visible=True
End Sub

Sub GLSV_Draw(gl As GL2)
    Try
        gl.glClear(Bit.Or(gl.GL_COLOR_BUFFER_BIT, gl.GL_DEPTH_BUFFER_BIT))
'        gl.glLoadIdentity()
'        gl.glTranslatef(0, 0, -5)
'        gl.glRotatef(EyeAngle * (180 / 3.14159), 0, 1, 0)
        
        DrawTINModel(gl)
    Catch
        Log(LastException)
    End Try
End Sub

Sub glsv_SurfaceChanged(gl As GL2, width As Int, height As Int)
    Log("Changed")
    Try
        gl.glViewport(0, 0, width, height)
        Dim ratio As Float = width / height
        gl.gluPerspective(45, ratio, 1, 100)
    Catch
        Log(LastException)
    End Try
End Sub
    
Sub glsv_SurfaceCreated(gl As GL2)
    Log("Created")
    Try
        gl.glClearColor(0, 0, 0, 1)
        gl.glEnable(gl.GL_DEPTH_TEST)
        gl.glDepthFunc(gl.GL_LESS)
    Catch
        Log(LastException)
    End Try
End Sub

Sub Timer1_Tick
    EyeAngle = EyeAngle + 0.1
    If EyeAngle > (2 * 3.14159) Then EyeAngle = EyeAngle - (2 * 3.14159)
    GlSV.RequestRender
End Sub

Sub GetVertices
    Dim i As Int
    
    i=0
    vertixes.Initialize
    Do While i<=CGlobals.MaxTins
        Y1=ConvertPhysicToCADX(CGlobals.Tin3D(i).East)
        X1=ConvertPhysicToCADY(CGlobals.Tin3D(i).North)
        vertixes.Add(Array As Float(X1, Y1, CGlobals.Tin3D(i).Elev)) ' x, y, height
        
        Y1=ConvertPhysicToCADX(CGlobals.Tin3D(i).East1)
        X1=ConvertPhysicToCADY(CGlobals.Tin3D(i).North1)
        vertixes.Add(Array As Float(X1, Y1, CGlobals.Tin3D(i).Elev1)) ' x, y, he
        
        Y1=ConvertPhysicToCADX(CGlobals.Tin3D(i).East2)
        X1=ConvertPhysicToCADY(CGlobals.Tin3D(i).North2)
        vertixes.Add(Array As Float(X1, Y1, CGlobals.Tin3D(i).Elev2)) ' x, y, he
        i=i+1
    Loop
    
    MinX=PntMinX
    MinY=PntMinY
    MaxX=PntMaxX
    MaxY=PntMaxY
    MinZ=CGlobals.ZMinCont
    MaxZ=CGlobals.ZMaxCont
    
End Sub

Sub CalculateScalingFactors
    ' Determine the range of your world coordinates
    Dim rangeX As Float = PntMaxX - PntMinX
    Dim rangeY As Float = PntMaxY - PntMinY
    Dim rangeZ As Float = CGlobals.ZMaxCont- CGlobals.ZMinCont

    ' Determine the dimensions of your screen or viewport
    Dim screenWidth As Float = Pnl3DView.Width
    Dim screenHeight As Float = Pnl3DView.Height

    ' Calculate the scaling factors
    Dim scaleFactorX As Float = screenWidth / rangeX
    Dim scaleFactorY As Float = screenHeight / rangeY

    ' Use the minimum of the two scaling factors to maintain aspect ratio
    Dim scaleFactor As Float = Min(scaleFactorX, scaleFactorY)

    ' Apply the same scaling factor to all axes
    ScaleX1 = scaleFactor
    ScaleY1 = scaleFactor
    ScaleZ1 = scaleFactor ' Assuming Z scaling is proportional to X and Y
End Sub

Sub DrawTINModel(gl As GL2)

'    If vertixes.Size < 3 Then
'        Log("Not enough vertices to draw a triangle")
'        Return
'    End If
'
'    Try
'        Dim jo As JavaObject = gl
'        jo.RunMethod("glEnableClientState", Array(gl.GL_VERTEX_ARRAY)) ' Enable vertex array
'
'        ' Define vertex pointer
'        jo.RunMethod("glVertexPointer", Array(3, gl.GL_FLOAT, 0, vertixes)) ' Assuming vertices is a Float array
'
'        ' Draw the vertices as triangles
'        jo.RunMethod("glDrawArrays", Array(gl.GL_TRIANGLES, 0, vertixes.Size / 3))
'
'        jo.RunMethod("glDisableClientState", Array(gl.GL_VERTEX_ARRAY)) ' Disable vertex array
'    Catch
'        Log("Exception during drawing: " & LastException)
'    End Try
End Sub

And my screen is black.

Thanks
Michael
 

amorosik

Expert
Licensed User
Hi, the proposed 3D view is part of the "Stockpile" activity, where one can import points from a csv file, create a TIN Model, generate contours, calculate volumes, etc.
I am attaching a file which you can import and also the "StockCalcs.bas" file which contains the complete code of the Activity.

Is not clear (almost for me)
How we can use the code in StockCalcs.bas ?
Is it enough to create a new project and copy the contents of StockCalcs.bas into the Main module?
 
Upvote 0

Terradrones

Active Member
Licensed User
Yes, create a new Project and call the StockCalcs from there. I forgot to add the other Activity which does the 3D plotting.

Here is the code:
B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
'    Dim Timer As Timer
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim Panel1, Panel2 As Panel
    Dim Butt1 As ImageView
    Dim Label As Label
    Dim triangle_c As Int
    Dim triangle(20000, 12) As Double '012-x0y0z0 345-x1y1z1 678-x2y2z2, 9,10,11 RGB
    Dim OpenGL As GLSurfaceView
    Dim Seekbar As SeekBar
    Dim Touchpanel_data(10) As Double
    Dim zoom_distance As Double
    Dim ScaleY,ScaleX,ScaleZ As Double
    Dim ScaledY,ScaledX,ScaledZ As Double
    Dim Imgv As ImageView
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("Plot3D")
    Activity.Title = "Plot 3D"
    Panel1.Visible = True
    Seekbar.Value = 50
    
    Panel2.Color = Colors.Transparent ' Make the panel transparent
    OpenGL.Initialize2(OpenGL.RENDERMODE_WHEN_DIRTY, "glsv", 16, 0)
    Panel2.AddView(OpenGL,0,0,Panel2.Width,Panel2.Height/2)
    Imgv.Initialize("")
    Panel2.AddView(Imgv,0,Panel2.Height/2,Panel2.Width,Panel2.Height/2)
    ScaleTin
'    Timer.Initialize("Timer", 100)
'    Timer.Enabled = True
End Sub

Sub Activity_Resume
    
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

#Region ******************************************************** Buttons Pressed ****************************************************

Sub Butt1_Click
    Activity.Finish
End Sub

#End Region

#Region ******************************************************* Calcs ************************************************************

Sub ScaleTin
    Dim Count, i As Int
    Dim ScreenDepth As Double = 300dip
    Dim Y1,X1,Z1,Y2,X2,Z2,Y3,X3,Z3 As Double
    
    Engine.GetTriangles(2)
    Count = CGlobals.MaxTins ' Number of Triangles
    
    ScaleY = Panel1.Width / (CGlobals.YMaxCoord - CGlobals.YMinCoord)
    ScaleX = Panel1.Height / (CGlobals.XMaxCoord - CGlobals.XMinCoord)
    ScaleZ = ScreenDepth / (CGlobals.ZMaxCont - CGlobals.ZMinCont)
    
    For i = 0 To Count - 1
        ScaleCoordinate(CGlobals.Tin3D(i).East,CGlobals.Tin3D(i).North,CGlobals.Tin3D(i).Elev)
        Y1=ScaledY
        X1=ScaledX
        Z1=ScaledZ
        ScaleCoordinate(CGlobals.Tin3D(i).East1,CGlobals.Tin3D(i).North1,CGlobals.Tin3D(i).Elev1)
        Y2=ScaledY
        X2=ScaledX
        Z2=ScaledZ
        ScaleCoordinate(CGlobals.Tin3D(i).East2,CGlobals.Tin3D(i).North2,CGlobals.Tin3D(i).Elev2)
        Y3=ScaledY
        X3=ScaledX
        Z3=ScaledZ
        Add_triangle(Y1,X1,Z1,Y2,X2,Z2,Y3,X3,Z3,0,0,0)
    Next
End Sub

Sub ScaleCoordinate(Y As Double, X As Double, z As Double) As List
    ScaledY = (Y - CGlobals.YMinCoord) * ScaleY
    ScaledX = (X - CGlobals.XMinCoord) * ScaleX
    ScaledZ = (Z - CGlobals.ZMinCont) * ScaleZ
    Return Array As Double(ScaledX, ScaledY, ScaledZ)
End Sub

Sub Add_triangle(x0 As Double, y0 As Double, z0 As Double, x1 As Double, y1 As Double, z1 As Double, x2 As Double, y2 As Double, z2 As Double, colr As Double, colg As Double, colb As Double)
    triangle(triangle_c, 0) = x0
    triangle(triangle_c, 1) = y0
    triangle(triangle_c, 2) = z0
    triangle(triangle_c, 3) = x1
    triangle(triangle_c, 4) = y1
    triangle(triangle_c, 5) = z1
    triangle(triangle_c, 6) = x2
    triangle(triangle_c, 7) = y2
    triangle(triangle_c, 8) = z2
    triangle(triangle_c, 9) = colr
    triangle(triangle_c, 10) = colg
    triangle(triangle_c, 11) = colb
    triangle_c = triangle_c + 1
End Sub

Sub Panel2_Touch (Action As Int, X As Double, Y As Double)
    If Action = Panel2.ACTION_MOVE Then
        Touchpanel_data(2) = Touchpanel_data(2) + (Touchpanel_data(0) - x) * .15
        Touchpanel_data(3) = Touchpanel_data(3) + (Touchpanel_data(1) - y) * .15
    End If
    Touchpanel_data(0) = X
    Touchpanel_data(1) = y
End Sub

Sub opengl_render_tick
    OpenGL.RequestRender
    Label.Text = "ANG1:" & NumberFormat(Touchpanel_data(2), 1, 1) & "  ANG2:" & NumberFormat(Touchpanel_data(3), 1, 1) & "  DISTANCE:" & NumberFormat(Abs(zoom_distance), 1, 1)
    Label.Invalidate
End Sub

Sub opengl_draw(gl As GL1)
    gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
    gl.glDisableClientState(gl.GL_TEXTURE_COORD_ARRAY)
    gl.glDisableClientState(gl.GL_NORMAL_ARRAY)
    
    gl.glClearColor(.8, .8, .8, 1)
    gl.glClear(Bit.Or(gl.GL_COLOR_BUFFER_BIT, gl.GL_DEPTH_BUFFER_BIT))
    gl.glEnable(gl.GL_NORMALIZE)
    gl.glLoadIdentity
    
    gl.glTranslatef(0, 0, zoom_distance)
    gl.glRotatef(-Touchpanel_data(3), 1, 0, 0)
    gl.glRotatef(-Touchpanel_data(2), 0, 1, 0)
    
    gl.glFrontFace(gl.GL_CCW)
    gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
    gl.glEnable(gl.GL_DEPTH_TEST)
    gl.glDepthFunc(gl.GL_LEQUAL)
    gl.glDepthMask(True)
    gl.glDisable(gl.GL_BLEND)
    
    gl.glPushMatrix
    
    Dim vertices(9) As Double
    For at = 0 To triangle_c - 1
        For t = 0 To 8
            vertices(t) = triangle(at, t)
        Next
        'gl.glVertexPointerf(3, vertices)
        gl.glColor4f(triangle(at, 9), triangle(at, 10), triangle(at, 11), 1) ' RGBA
        gl.glDrawArrays(gl.GL_TRIANGLES, 0, 3)
    Next
    
    gl.glPopMatrix
    gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
End Sub

Sub opengl_SurfaceChanged(gl As GL1, width As Int, height As Int)
    gl.glViewport(0, 0, width, height)
    gl.glMatrixMode(gl.GL_PROJECTION)
    gl.gluPerspective(60, width / height, 0.01, 6)
    gl.glMatrixMode(gl.GL_MODELVIEW)
End Sub

Sub SeekBar_ValueChanged (Value As Int, UserChanged As Boolean)
    zoom_distance = -(100 - Value) * .05
End Sub
 
Upvote 0

amorosik

Expert
Licensed User
Yes, create a new Project and call the StockCalcs from there. I forgot to add the other Activity which does the 3D plotting.

Here is the code:
B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
'    Dim Timer As Timer
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim Panel1, Panel2 As Panel
    Dim Butt1 As ImageView
    Dim Label As Label
    Dim triangle_c As Int
    Dim triangle(20000, 12) As Double '012-x0y0z0 345-x1y1z1 678-x2y2z2, 9,10,11 RGB
    Dim OpenGL As GLSurfaceView
    Dim Seekbar As SeekBar
    Dim Touchpanel_data(10) As Double
    Dim zoom_distance As Double
    Dim ScaleY,ScaleX,ScaleZ As Double
    Dim ScaledY,ScaledX,ScaledZ As Double
    Dim Imgv As ImageView
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("Plot3D")
    Activity.Title = "Plot 3D"
    Panel1.Visible = True
    Seekbar.Value = 50
   
    Panel2.Color = Colors.Transparent ' Make the panel transparent
    OpenGL.Initialize2(OpenGL.RENDERMODE_WHEN_DIRTY, "glsv", 16, 0)
    Panel2.AddView(OpenGL,0,0,Panel2.Width,Panel2.Height/2)
    Imgv.Initialize("")
    Panel2.AddView(Imgv,0,Panel2.Height/2,Panel2.Width,Panel2.Height/2)
    ScaleTin
'    Timer.Initialize("Timer", 100)
'    Timer.Enabled = True
End Sub

Sub Activity_Resume
   
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

#Region ******************************************************** Buttons Pressed ****************************************************

Sub Butt1_Click
    Activity.Finish
End Sub

#End Region

#Region ******************************************************* Calcs ************************************************************

Sub ScaleTin
    Dim Count, i As Int
    Dim ScreenDepth As Double = 300dip
    Dim Y1,X1,Z1,Y2,X2,Z2,Y3,X3,Z3 As Double
   
    Engine.GetTriangles(2)
    Count = CGlobals.MaxTins ' Number of Triangles
   
    ScaleY = Panel1.Width / (CGlobals.YMaxCoord - CGlobals.YMinCoord)
    ScaleX = Panel1.Height / (CGlobals.XMaxCoord - CGlobals.XMinCoord)
    ScaleZ = ScreenDepth / (CGlobals.ZMaxCont - CGlobals.ZMinCont)
   
    For i = 0 To Count - 1
        ScaleCoordinate(CGlobals.Tin3D(i).East,CGlobals.Tin3D(i).North,CGlobals.Tin3D(i).Elev)
        Y1=ScaledY
        X1=ScaledX
        Z1=ScaledZ
        ScaleCoordinate(CGlobals.Tin3D(i).East1,CGlobals.Tin3D(i).North1,CGlobals.Tin3D(i).Elev1)
        Y2=ScaledY
        X2=ScaledX
        Z2=ScaledZ
        ScaleCoordinate(CGlobals.Tin3D(i).East2,CGlobals.Tin3D(i).North2,CGlobals.Tin3D(i).Elev2)
        Y3=ScaledY
        X3=ScaledX
        Z3=ScaledZ
        Add_triangle(Y1,X1,Z1,Y2,X2,Z2,Y3,X3,Z3,0,0,0)
    Next
End Sub

Sub ScaleCoordinate(Y As Double, X As Double, z As Double) As List
    ScaledY = (Y - CGlobals.YMinCoord) * ScaleY
    ScaledX = (X - CGlobals.XMinCoord) * ScaleX
    ScaledZ = (Z - CGlobals.ZMinCont) * ScaleZ
    Return Array As Double(ScaledX, ScaledY, ScaledZ)
End Sub

Sub Add_triangle(x0 As Double, y0 As Double, z0 As Double, x1 As Double, y1 As Double, z1 As Double, x2 As Double, y2 As Double, z2 As Double, colr As Double, colg As Double, colb As Double)
    triangle(triangle_c, 0) = x0
    triangle(triangle_c, 1) = y0
    triangle(triangle_c, 2) = z0
    triangle(triangle_c, 3) = x1
    triangle(triangle_c, 4) = y1
    triangle(triangle_c, 5) = z1
    triangle(triangle_c, 6) = x2
    triangle(triangle_c, 7) = y2
    triangle(triangle_c, 8) = z2
    triangle(triangle_c, 9) = colr
    triangle(triangle_c, 10) = colg
    triangle(triangle_c, 11) = colb
    triangle_c = triangle_c + 1
End Sub

Sub Panel2_Touch (Action As Int, X As Double, Y As Double)
    If Action = Panel2.ACTION_MOVE Then
        Touchpanel_data(2) = Touchpanel_data(2) + (Touchpanel_data(0) - x) * .15
        Touchpanel_data(3) = Touchpanel_data(3) + (Touchpanel_data(1) - y) * .15
    End If
    Touchpanel_data(0) = X
    Touchpanel_data(1) = y
End Sub

Sub opengl_render_tick
    OpenGL.RequestRender
    Label.Text = "ANG1:" & NumberFormat(Touchpanel_data(2), 1, 1) & "  ANG2:" & NumberFormat(Touchpanel_data(3), 1, 1) & "  DISTANCE:" & NumberFormat(Abs(zoom_distance), 1, 1)
    Label.Invalidate
End Sub

Sub opengl_draw(gl As GL1)
    gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
    gl.glDisableClientState(gl.GL_TEXTURE_COORD_ARRAY)
    gl.glDisableClientState(gl.GL_NORMAL_ARRAY)
   
    gl.glClearColor(.8, .8, .8, 1)
    gl.glClear(Bit.Or(gl.GL_COLOR_BUFFER_BIT, gl.GL_DEPTH_BUFFER_BIT))
    gl.glEnable(gl.GL_NORMALIZE)
    gl.glLoadIdentity
   
    gl.glTranslatef(0, 0, zoom_distance)
    gl.glRotatef(-Touchpanel_data(3), 1, 0, 0)
    gl.glRotatef(-Touchpanel_data(2), 0, 1, 0)
   
    gl.glFrontFace(gl.GL_CCW)
    gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
    gl.glEnable(gl.GL_DEPTH_TEST)
    gl.glDepthFunc(gl.GL_LEQUAL)
    gl.glDepthMask(True)
    gl.glDisable(gl.GL_BLEND)
   
    gl.glPushMatrix
   
    Dim vertices(9) As Double
    For at = 0 To triangle_c - 1
        For t = 0 To 8
            vertices(t) = triangle(at, t)
        Next
        'gl.glVertexPointerf(3, vertices)
        gl.glColor4f(triangle(at, 9), triangle(at, 10), triangle(at, 11), 1) ' RGBA
        gl.glDrawArrays(gl.GL_TRIANGLES, 0, 3)
    Next
   
    gl.glPopMatrix
    gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
End Sub

Sub opengl_SurfaceChanged(gl As GL1, width As Int, height As Int)
    gl.glViewport(0, 0, width, height)
    gl.glMatrixMode(gl.GL_PROJECTION)
    gl.gluPerspective(60, width / height, 0.01, 6)
    gl.glMatrixMode(gl.GL_MODELVIEW)
End Sub

Sub SeekBar_ValueChanged (Value As Int, UserChanged As Boolean)
    zoom_distance = -(100 - Value) * .05
End Sub

I'm lost
I don't understand if after creating an empty Bx4Pages project, and after loading the new StockCalcs.bas module it is necessary to create something else
Could you post the complete project?
 
Upvote 0

amorosik

Expert
Licensed User
Yes, sure
Knowing exactly what you are referring to when you write 3DPlot I could search for it myself
Searching on the forum however, no library/project with this name appears
Searching on Google does not either
Be patient, but when you write '3DPlot' what exactly are you referring to?


1730891599798.png




1730891616277.png
 
Upvote 0

Terradrones

Active Member
Licensed User
When the Surveyor logs points on say a Stockpile of material with either a GPS or Total Station, these points can be imported into the program. Each point consists of X, Y and Z coordinates. The survey can then be triangulated using Delaunay theory. I can already shade the survey using the heights of each vertex in the model. What would be nice to have, is to be able to view the survey in 3D and zoom in\out and rotate the model. That is what I am trying to do using OpenGL in the "3DPlot" code.

It does not add any productive action for the Surveyor....just nice to have.
 
Upvote 0

amorosik

Expert
Licensed User
In addition to seeing it in 3D, it would be interesting to be able to calculate the section
In order to calculate the volume of the mound of material (or the difference compared to a previous reading)
 
Upvote 0
Top