Android Code Snippet [BAX] [XUI] BitmapCreator - DrawLine, DrawPath , DrawCircle, DrawArc, DrawImageTrapezoid

Discussion in 'Code Snippets' started by Star-Dust, Jun 20, 2018.

  1. Star-Dust

    Star-Dust Expert Licensed User

    BitmapCreator lacks some important instructions on Canvas.
    Sometimes switching from BitmapCreator to Canvas and vice versa would slow down the code too much, so it would be better to implement them with BitmapCreator.

    I started writing some divers, if someone finds a way to improve it or add other features put other posts.

    P.S. Please do not fill the thread with questions and requests for explanations. Open a thread in the questions section

     
  2. Star-Dust

    Star-Dust Expert Licensed User

    DRAW LINE
    Code:
    Private Sub Drawline(BC As BitmapCreator, x1 As Int, y1 As Int, x2 As Int, y2 As Int, Color As Int)
        
    Dim Dx,Dy,Diff As Int
        
    Dim x,y As Float
     
        Dx = x2 - x1
        Dy = y2 - y1
        Diff=
    Max(Abs(Dx),Abs(Dy))
        
    For D=0 To Diff
            x= x1 + Dx*D/Diff
            y = y1 + Dy*D/Diff
            
    If (x>=0 And x<BC.mWidth) And (y>=0 And y<BC.mHeight) Then BC.SetColor(x,y,Color)
        
    Next
    End Sub


    DRAW PATH (Empty)
    Code:
    Type Point_Type(X as int, Y as int)

        
    Private Sub DrawPathEmpty(BC As BitmapCreator, VerticesList As List, Color As Int)
        
    Dim X,Y As Int
     
        
    Dim P As Point_Type = VerticesList.Get(PointList.Size-1)
        X=P.X
        Y=P.Y
     
        
    For Each P As Point_Type In VerticesList
            Drawline(BC,X,Y,P.X,P.Y, Color)
            X=P.X
            Y=P.Y
        
    Next
        
    End Sub
    This sub traces the lines defined by the vertices with the path system. He needs the Sub DrawLine present in this same post
     
    Last edited: Jun 21, 2018
  3. Star-Dust

    Star-Dust Expert Licensed User

    DRAW PATH (FILL)
    Algorithm ScanLine

    Update 0.01
    Code:
    Public Sub IsLimit(BC As BitmapCreator,x As Int, y As Int) As Boolean
        
    Dim cp As Int = x * 4 + y * BC.mWidth * 4
        
    Return BC.Buffer(cp + 3) = 01
    End Sub

    Private Sub DrawPathFill(BC As BitmapCreator,PointList As List, Color As Int)
        
    Dim aColor As ARGBColor = ColorToARGB(Color)
        
    Dim P As Point_Type = PointList.Get(PointList.Size-1)
        
    Dim Xl As Int = P.X
        
    Dim Yl As Int = P.Y
        
    Dim MaxX As Int = Xl
        
    Dim MinX As Int = Xl
        
    Dim MaxY As Int = Yl
        
    Dim MinY As Int = Yl

        
    Dim Alimit As ARGBColor = ColorToARGB(xui.Color_ARGB(1,0,0,0))
        
    For Each P As Point_Type In PointList
                
    Dim Dx,Dy,Diff As Int
                
    Dim x,y As Float

                Dx = P.x - Xl
                Dy = P.Y - Yl
                Diff=
    Max(Abs(Dx),Abs(Dy))
                x = Xl
                y = Yl
                
    Dim tx  As Double = Dx / Diff
                
    Dim ty  As Double = Dy / Diff
                
    For D=0 To Diff
                    BC.SetARGB(x, y, Alimit)
                    X = 
    Min(Max(x + tx,0),BC.mWidth-1)
                    Y = 
    Min(Max(Y + ty,0),BC.mHeight-1)
                
    Next
            
    ID=ID+1
            Xl=P.X
            Yl=P.Y
        
    Next
      
        
    For Each P As Point_Type In PointList
            AddTouch(
    ID,ID,P.X,P.Y)
            MinX=
    Min(MinX,P.X)
            MaxX=
    Max(MaxX,P.X)
            MinY=
    Min(MinY,P.y)
            MaxY=
    Max(MaxY,P.y)
        
    Next
      
        
    For y=MinY To MaxY
            
    Dim StartX As Int = BC.mWidth
            
    Dim StopX As Int = -1
            
    For x=MinX To MaxX
                
    If IsLimit(BC,x,y) Then
                    StartX=
    Min(StartX,x)
                    StopX=
    Max(StopX,x)
                
    End If
            
    Next
          
            
    Dim B As Boolean = False
            
    For x=StartX To StopX
                
    If IsLimit(BC,x,y) Then
                    
    If  Not(b) Then
                        B=
    True
                    
    Else
                        
    If IsLimit(BC,x,y)=False Then B=False
                    
    End If
                    BC.SetARGB(x,y,aColor)
                
    End If
                
    If b Then BC.SetARGB(x,y,aColor)
            
    Next
        
    Next

    End Sub
    This sub refers to the other two of the previous post.
    Unfortunately this procedure is slower than canvas, but I have to try other more efficient algorithms
     
    Last edited: Jun 21, 2018
  4. Star-Dust

    Star-Dust Expert Licensed User

    Circle

    Code:
    Private Sub DrawCircleEmpty(BC As BitmapCreator, x As Int, y As Int, Radial As Int , BorderColor As Int)
        
    Dim X1 As Double = X + Radial * CosD(0)
        
    Dim Y1 As Double = Y + Radial * SinD(0)
      
        
    For i=1 To 720
            
    Dim X2 As Double = X + Radial * CosD(i/2)
            
    Dim Y2 As Double = Y + Radial * SinD(i/2)
            Drawline(BC,X1,Y1,X2,Y2,BorderColor)
            X1 = X2
            Y1 = Y2
        
    Next
    End Sub
    Arc
    Code:
    Private Sub DrawArcEmpty(BC As BitmapCreator, x As Int, y As Int, Radial As Int, StartDegree As Int, EndDegree As Int,BorderColor As Int)
        
    Dim X1 As Double = X + Radial * CosD(StartDegree)
        
    Dim Y1 As Double = Y + Radial * SinD(StartDegree)
      
        Drawline(BC,X1,Y1,X,Y,BorderColor)
        
    For i=(StartDegree*2)+1 To EndDegree*2
            
    Dim X2 As Double = X + Radial * CosD(i/2)
            
    Dim Y2 As Double = Y + Radial * SinD(i/2)
            Drawline(BC,X1,Y1,X2,Y2,BorderColor)
            X1 = X2
            Y1 = Y2
        
    Next
        Drawline(BC,X1,Y1,X,Y,BorderColor)
    End Sub
    In the cycle I put the degrees from 0 to 720, but I divide by 2, so to get 0-360 with step 0.5.

    The higher the value of the greater radius must be the precision then decrease the step of the cycle, otherwise we see the steps between the lines.
     
    Last edited: Jun 20, 2018
  5. Star-Dust

    Star-Dust Expert Licensed User

    Draw Bitmap to Trapezoid Form
    upload_2018-6-21_17-46-54.png

    We normally draw the images into rectangles and save them in a byte array, which is similar to a rectangle.
    But sometimes there is the need to design an image that is born rectangular inside a trapezium and/or rotate them, as in the case of perspectives. (see image)
    How to do?
    I tried several algorithms found on the internet and graduated tsins on the graphics, but they all had bugs. So I created one myself, it's not the most performing,, but it works and does not crash.

    Code:
    Type Point_Type(X as Int, Y as int)

    Private Sub Trapezoid(bmp As BitmapCreator, BitTrap As BitmapCreator, p1 As Point_Type, p2 As Point_Type, p3 As Point_Type, p4 As Point_Type ) 'As B4XBitmap
        Dim XmaX As Int = bmp.mWidth-1
        
    Dim Ymax As Int = bmp.mHeight-1
        
    Dim Ystart,Xstart,Yend, Xend As Float
        
    Dim YstartNext,YendNext,Ynext,XstartNext As Float
        
    Dim XNow,YNow,XendNext,Xnext,xg As Float
        
    Dim Rec As B4XRect

            
    For Y = 0 To Ymax
           
                Ystart=p1.Y+((p3.Y-p1.Y)*y/Ymax)
                Yend=p2.Y+((p4.Y-p2.Y)*Y/Ymax)
                YstartNext=p1.Y+((p3.Y-p1.Y)*(y+
    1)/Ymax)
                YendNext=p2.Y+((p4.Y-p2.Y)*(Y+
    1)/Ymax)
           
                Xstart=p1.X+((p3.X-p1.X)*y/Ymax)
                Xend=p2.X+((p4.X-p2.X)*Y/Ymax)
                XstartNext=p1.X+((p3.X-p1.X)*(y+
    1)/Ymax)
                XendNext=p2.X+((p4.X-p2.X)*(Y+
    1)/Ymax)
       
                
    For X=0 To XmaX
                    XNow=Xstart+(((Xend-Xstart)*x/XmaX))
                    YNow=Ystart+(((Yend-Ystart)*x/XmaX))
                    Xnext=XstartNext+(((XendNext-XstartNext)*(x+
    1)/XmaX))
                    Ynext=YstartNext+(((YendNext-YstartNext)*(x+
    1)/XmaX))
                    
    If Abs(XNow-Xnext)<1dip Then Xnext=XNow+sign(Xnext-XNow)*1dip
                    
    If Abs(YNow-Ynext)<1dip Then Ynext=YNow+sign(Ynext-YNow)*1dip

                    
    If XNow>Xnext Then
                        xg=XNow
                        XNow=Xnext
                        Xnext=xg
                    
    End If
                       
                    
    If YNow>Ynext Then
                        xg=YNow
                        YNow=Ynext
                        Ynext=xg
                    
    End If
                    Rec.Initialize(XNow+BitTrap.TargetRect.CenterX,YNow+BitTrap.TargetRect.CenterY,Xnext+BitTrap.TargetRect.CenterX,Ynext+BitTrap.TargetRect.CenterY)
                    BitTrap.FillRect(bmp.GetColor(X,Y),Rec)
                
    Next
            
    Next
    End Sub
     
    Last edited: Jun 21, 2018
  6. Erel

    Erel Administrator Staff Member Licensed User

    A small change that can significantly improve the performance:
    Code:
    Private Sub Drawline(bc As BitmapCreator, x1 As Int, y1 As Int, x2 As Int, y2 As Int, Color As Int)
       
    Dim Dx,Dy,Diff As Int
       
    Dim x,y As Float
         
    Dim a As ARGBColor
       bc.ColorToARGB(Color, a)
       Dx = x2 - x1
       Dy = y2 - y1
       Diff=
    Max(Abs(Dx),Abs(Dy))
       x = x1
       y = y1
       
    Dim tx = Dx / Diff, ty = Dy / Diff As Float
       
    For D=0 To Diff
           
    If (x>=0 And x<bc.mWidth) And (y>=0 And y<bc.mHeight) Then
               bc.SetARGB(x, y, a)
           
    End If
           x = x + tx
           y = y + ty
       
    Next
    End Sub
    There are two changes:
    1. Using SetARGB is faster than SetColor though at least in B4J the difference is not large.
    2. You should do as few as possible calculations inside the loop.

    This is still not the most optimized solution.
     
    hibrid0, Peter Simpson and Star-Dust like this.
  7. Erel

    Erel Administrator Staff Member Licensed User

    Note that BitmapCreator.FillRect is much faster (x8 in B4J, probably more in B4i) than the DrawRec method with Filled = True.
     
    Star-Dust likes this.
  8. Star-Dust

    Star-Dust Expert Licensed User

    Surely it is faster, I should be able to access the bitmapCreator ByteData to speed up all the functions.
    But I think it's not possible, or am I wrong?

    If it were possible to rewrite the functions with faster methods.
     
  9. Star-Dust

    Star-Dust Expert Licensed User

    This is also true. I did not optimize it because the result was equally satisfying (for me :p)

    What needs significant improvements is the DrawPathFill, I was focusing on that. I have tried many algorithms but all not very efficient for a mobile device.
     
  10. Erel

    Erel Administrator Staff Member Licensed User

    BC.Buffer returns the internal array. Though I don't see how it will help with most of the above methods.
     
    Star-Dust likes this.
  11. Star-Dust

    Star-Dust Expert Licensed User

    I realized it was read-only in the sense that you could not change the bytes of the array :confused:
     
  12. Erel

    Erel Administrator Staff Member Licensed User

    It will not help with the above methods. SetColor / SetARGB directly change this array. It is possible to set a single pixel a bit faster with CopyPixel however it will not have a large impact.

    The algorithm you are using for DrawPathFill is very inefficient. You shouldn't call GetColor at all. You should instead calculate all the limits while drawing the lines.
    However a probably better solution is to draw with B4XCanvas and then convert the bitmap to BitmapCreator.
     
    Star-Dust likes this.
  13. Star-Dust

    Star-Dust Expert Licensed User

    Already tried and it is slightly slower.
    The thing that slows down more is the transition from B4Xcanvas to BitmapCreator.

    I will try to implement your suggestions and see what I get.
    Furthermore, for the remediation I found more efficient algorithms. I have yet to test them
     
  14. Erel

    Erel Administrator Staff Member Licensed User

    If you like you can upload a small example and I'll try to optimize it.
     
    Star-Dust likes this.
  15. Star-Dust

    Star-Dust Expert Licensed User

    I used this code with B4XCanvas.

    I also thought of generating a Canvas only for the area of the polygon.
    For design the rubik's cube takes 0.20 - 0.36 sec
    ScanLine Algoritm,that I use in my code, with the changes you suggested, takes 0.15 - 0.20 sec for design the rubik's cube

    Code:
    Private Sub DrawPathFill2(BC As BitmapCreator,PointList As List, Color As Int)
        
    Dim P As Point_Type = PointList.Get(PointList.Size-1)
        
    Dim MinX As Int = P.X
        
    Dim MaxX As Int = P.X
        
    Dim MinY As Int = P.Y
        
    Dim MaxY As Int = P.Y
     
     
        
    For Each P As Point_Type In PointList
            MinX=
    Min(MinX,P.X)
            MaxX=
    Max(MaxX,P.X)
            MinY=
    Min(MinY,P.y)
            MaxY=
    Max(MaxY,P.y)
        
    Next
     
        
    Dim V As B4XView = xui.CreatePanel("")
        V.SetLayoutAnimated(
    0,0,0,Abs(MaxX-MinX)+1,Abs(MaxY-MinY)+1)

        
    Dim Can As B4XCanvas
        Can.Initialize(V)
        
    Dim Rec As B4XRect
        Rec.Initialize(
    0,0,Abs(MaxX-MinX)+1,Abs(MaxY-MinY)+1)
        
        
    Dim Path As B4XPath
        
    Dim P As Point_Type = PointList.Get(PointList.Size-1)
     
        
    Path.Initialize(P.X-MinX,P.Y-MinY)
     
        
    For Each P As Point_Type In PointList
            
    Path.LineTo(P.x-MinX,P.y-MinY)
        
    Next
     
        Can.DrawPath(
    Path,Color,True,1)
        Rec.Initialize(MinX,MinY,MaxX,MaxY)
        BC.DrawBitmap(Can.CreateBitmap,Rec,
    False)
    End Sub
    At the moment although my algorithm is inefficient it is better than Canvas.

    I will try to use the FloodFill algorithm, which they say is better. is bad and slower.

    If I fall below 0.10 sec for me it is already a goal. The ideal would be to design it 0.02-0.04 sec

    In the previous version of my library I used only B4XCanvas (for polygon) and BitmapCreator (for Images) used 0.02-0.04 for the rubik's cube and 0.16-0.19 for the image.
    Using BitmapCreator I take 0,15-0,19 for the Rubik's Cube and 0,07-0,09 for the images
    I gained in the immgini but I lost in the polygons.
     
    Last edited: Jun 21, 2018
  16. Star-Dust

    Star-Dust Expert Licensed User

    Update:
    I go a little bit off the topic, but to better explain the question.
    I modified my library, where I use this sub, for a better compromise between Canvas and BitmapCreator.

    Now i'm using B4XCavas to the sight and I draw all the polygons. For images, I create a BitmapCreator with the image size, I process the pixels and I design the BitmapCreator in the Cavas and I'm getting better performance.

    Previously I turned the entire B4XCavas into Bitmap and then Bitmap into BitmapCreator. I made the process to the image and finally I drew the BitmapCreator resulting in the Canvas. This was extremely slow.

    Now the times are these:

    Rubik's cube: 0,02-0,04 sec
    Image: 0.04-0.06 sec


    Conclusions:
    1. Having a BitmapCreator as big as View,helps if you have to draw images, but slow down with the polygons full.
    2. Having a View/B4XCanvas, helps the polygons but slows down the images.
    3. Having a BitmapCreator as big as the view and drawing images, but use Canvas for polygons, is discreet compromise.
    4. Using a view/B4XCanvas to draw polygons and creating little BitmapCreator for images to copy on canvas is better
    Now I return to the main topic as the title
     
    Last edited: Jun 21, 2018
    Erel likes this.
  17. Star-Dust

    Star-Dust Expert Licensed User

    Almora likes this.
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice