Android Question DIP vs pixels

Pravin Shah

Member
Licensed User
Longtime User
Hi there,

I am drawing a chart (image attached) using canvas. On the chart I wanted to find out which rectangle is clicked and based on that take some action. I am using following logic -
- If it is a singleclick then take X & Y coordinate
- Run through each rectangle's X1,Y1 and X2,Y2 and find out under which rectangle these X, Y coordinates lies.
- The issue is that I am using dip unit to draw rectangle and storing its X1,Y1 and X2,Y2 values in dip unit. However the X, Y coordinates gives me values in pixels and there is vast difference between pixels and dips unit so no match is found.
My question
is how can I convert Dip to pixels or vice versa? What is the conversion factor?
Is there any other way to find out which rectangle is clicked by user? I am using canvas.drawrect method to draw rectangles.
 

Attachments

  • Screenshot_2014-12-11-19-09-30.png
    Screenshot_2014-12-11-19-09-30.png
    117.5 KB · Views: 335

klaus

Expert
Licensed User
Longtime User
Convert dip to pixels use:
DipToCurrent(Length As Int)
The conversion factor is GetDeviceLayoutValues.Scale.
If you set rect1.Initialize(10dip, 10dip, 110dip, 110dip).
And then you call rect1.Left, rect1.Top, rect1.Right and rect1.Bottom you get pixels in return.
 
Upvote 0

Pravin Shah

Member
Licensed User
Longtime User
Thanks klaus.. the above code work properly and it gives values in pixels.

But I am sorry as I did not put my requirement properly. Actually I am using PinchZoomAndMove library to zoom in and out of the chart. Due to zoom, the X, Y coordinates which I am getting are not consistent (they vary as per the zoom % - hope I am clear). Due to this I am not able to get the correct position of rectangle. It looks like it is difficult to identify clicked rectangle using this logic.

I tried alternative logic of adding panels and capturing it's click event instead of drawing rects but these panels do not get zoom when I try Pinch & Zoom, they remain at their original position. I am using following code to draw the chart and attach PinchZoomAndMove to the panel.
B4X:
Dim Cvs As Canvas
    Cvs.Initialize(Panel2)
  'Cvs.Initialize2(bmp)
    DrawNode(Node, Cvs, Panel2)
    'Panel2.SetBackgroundImage(bmp)

    Panel2.Invalidate
    Dim Pz As PinchZoomAndMove
    Dim c As Int
    Pz.Initialize(Panel2,"PZ",c,0.5,5,20,True,Me)

In the drawnode method, I am adding panel for each node using following code. When the chart loads for the first time, it shows properly alongwith panel but when zoom is applied then it goes haywire (image attached)
B4X:
NodeRect.Initialize(Node.X1, Node.Y1, Node.X2, Node.Y2)       
    ParentPnl.AddView(Pnl,Node.X1,Node.Y1,Node.X2 - Node.X1,Node.Y2 - Node.Y1)
    Pnl.Color = Colors.Cyan

What could be the better way to capture clicked node in this scenario? Thanks in advance
 

Attachments

  • Screenshot_2014-12-12-07-04-56.png
    Screenshot_2014-12-12-07-04-56.png
    120.7 KB · Views: 646
Upvote 0

Pravin Shah

Member
Licensed User
Longtime User
I am not redrawing the chart. I have added Panel object to Canvas and drawn rects & line on Panel to show the tree. For zoom, I am using class PinchZoomAndMove (created by Giancarlo "Dominex" Fioretti) which has internal methods to zoom in and out. I am passing panel as the parameter and the class applies zoom methods on this object.
It looks like since tree is drawn on this panel it also gets zoomed. That is the reason I tried adding small panels to this Parent Panel thinking it will act as container and these small panels will get zoomed alongwith the parent panel but that is not happening.

Calculating standard coordinates knowing zoom factor is difficult as I am allowing the tree to be moved around as well alongwith the zoom.

I have attached sample apk file which will give idea about what is happening.

Just thinking loud - instead of drawing rects, I should add panel or any other views on the parent panel and it will be easier to capture the click event for the same. However the issue is that it should also get proportionately zoomed alongwith the parent panel.
 

Attachments

  • TestTree1.apk
    172.6 KB · Views: 267
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
Maybe we need to think outside of the box (pun fully intended ;)). My suggestion would be to alter the colour of each box very slightly, it would not need to be noticable by eye but so that you can then get the pixel color that was pressed and know which box that colour related to. Should be simple and reliable.

Regards,
RandomCoder
 
Upvote 0

Pravin Shah

Member
Licensed User
Longtime User
I have attached the zip file of the project. Please let me know if you need additional details. Thanks for your help.

Edit - Please note that I will be adding image in each rect and below that the name of the person. Just wanted to give full requirements so that we can find better solution.
 

Attachments

  • TestTree - Demo.zip
    65.1 KB · Views: 245
Last edited:
Upvote 0

Pravin Shah

Member
Licensed User
Longtime User
Maybe we need to think outside of the box (pun fully intended ;)). My suggestion would be to alter the colour of each box very slightly, it would not need to be noticable by eye but so that you can then get the pixel color that was pressed and know which box that colour related to. Should be simple and reliable.

Regards,
RandomCoder

Thanks RandomCoder, I will look into the solution. But I missed to mention that each rect will have an image so when I get the pixel color it will belong to image so again it will be difficult to find which rect the image belong to. I hope I am not wrong.
 
Upvote 0

Pravin Shah

Member
Licensed User
Longtime User
I was experimenting with it and I tried drawing bitmap in the rect (using following line) and this image is getting zoomed alongwith the other part
Cvs.DrawBitmap(Image,Null,NodeRect)

But I am not sure how to capture click event of the image as there are no events associated with the Bitmap object.
 
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
I was experimenting with it and I tried drawing bitmap in the rect (using following line) and this image is getting zoomed alongwith the other part
Cvs.DrawBitmap(Image,Null,NodeRect)

But I am not sure how to capture click event of the image as there are no events associated with the Bitmap object.

You don't mention where you are drawing your chart, but if the canvas is added to a panel or the activity then you can use its touch event. Here is a sample that I'm using for a game that I intend to enter into the mini game competition....
B4X:
Private Sub GameBoard_Touch(Action As Int, X As Float, Y As Float)
    ' Get pixel color on first touch only
    If Action = pnlGameBoard.ACTION_DOWN Then
        Dim intTouchColor As Int = cvsGameZone.Bitmap.GetPixel(X, Y)
        If intTouchColor <> intGameBoardColor Then
            ' Elf has been caught, hide and play random sound
            Elf_Hide
            intHitCount = intHitCount + 1
            lblHitCount.Text = intHitCount
            audSoundPool.Play(arrAudio(Rnd(0, 4)), 1, 1, 1, 0, 1)
        End If
    End If
End Sub
In the above sub I am simply checking if the pixel color is the same as the background and if not then I assume that my elf image must have been hit. It's very simply!
Maybe you you could just alter the Alpha layer of the image and check this value? I don't know if it will work although I intend to try it for my next stage of the game, however I've not got time now as I need to pick my son up from school!!! Just thought I'd offer up a quick solution in case you were waiting on an answer.

Erel has already posted a solution to get ARGB values from an int...
B4X:
Sub Activity_Create(FirstTime As Boolean)
    Dim argb() As Int
    argb = GetARGB(Colors.Transparent)
    Log("A = " & argb(0))
    Log("R = " & argb(1))
    Log("G = " & argb(2))
    Log("B = " & argb(3))
End Sub

Sub GetARGB(Color As Int) As Int()
    Dim res(4) As Int
    res(0) = Bit.UnsignedShiftRight(Bit.And(Color, 0xff000000), 24)
    res(1) = Bit.UnsignedShiftRight(Bit.And(Color, 0xff0000), 16)
    res(2) = Bit.UnsignedShiftRight(Bit.And(Color, 0xff00), 8)
    res(3) = Bit.And(Color, 0xff)
    Return res
End Sub

Original post can be found here... https://www.b4x.com/android/forum/threads/how-to-convert-int-to-r-g-b-trans.12021/#post-67346
 
Upvote 0

Pravin Shah

Member
Licensed User
Longtime User
I had created a subproject and missed to add both the files earlier. I am attaching new zip file now, please use the same now. thanks
 

Attachments

  • TestTree - Demo.zip
    265.8 KB · Views: 256
Upvote 0

klaus

Expert
Licensed User
Longtime User
I had a look at your program.
Sorry, but it would take too much time to dive deeper in your project , I have never worked with TouchImageViews nor with Gestures and this would need that I learn these functionalites before going further.
I was thinking that you redrew the chart after the zooming, that way you would have known the new coordinates.
With Gesture, I think you can get the coordinates when you touch the panel.
What coordinates do you get ?
Zoomed coordinates, or original coordinates ?
With the zoom factor you should be able to calculate 'standard' coordinates corresponding to the node coordinates.
And with these coordinates determine which rectangle was touched.
 
Last edited:
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
I too have had a look and added a transparent layer over each node (Alpha value varies slightly for each node) but unfortunately the X and Y co-ordinates from the touch event does not correspond to the original bitmap size. I do not know how to scale them back to a value that could be used. Sorry.
 
Upvote 0

Pravin Shah

Member
Licensed User
Longtime User
Thanks @klaus and @RandomCoder for your help and suggestions. I did some research and modified the code of Pinch and Zoom library to get the relative X, Y coordinates based on movement and current zoom size. Now I am able to identify the clicked rectangle in my initial test.

Appreciate your time and help.. thanks again!!
 
Upvote 0
Top