Important: Please read the Qt Code of Conduct -

Implementing surface level in QML

  • Hi,

    I am trying to implement surface level in QML using rotation sensor keeping a bubble image inside a circle. When I move the mobile on x,y,z axis the bubble should move accordingly.

    I am using the x,y coordinates of the bubble image as the origin and changing it according to the following equations
    new x = originx + cos(reading.xpi/180)radius
    new y=originy + cos(reading.x

    HOwever, it is not moving in to the 1st and fourth quadrant at all. Anyone has any ideas as to where I am going wrong?

  • I am pretty sure you need a sin() somewhere... your code should look like :

    newX = cos( yourAngle ) * oldX - sin( yourAngle ) * oldY;
    newY = cos( yourAngle ) * oldY + sin( yourAngle ) * oldX;

    Basically a rotation is defined by a 2x2 matrix which has determinant +1, your example doesn't fit this requirement.

  • Oops, I meant new y=originy + sin(reading.x*pi/180)*radius. I would like to move the bubble image within the defined circle depending on the rotation angle

  • I have defined prevX and prevY initially to be at the centre of the circle. Would this work?

    @ bubbleImage.x = (Math.cos( reading.x * (Math.PI/180) ) * bubbleImage.prevX) - (Math.sin( reading.x * (Math.PI/180) ) * bubbleImage.prevY);
    bubbleImage.y = (Math.cos(reading.y * (Math.PI/180) ) * bubbleImage.prevY) + (Math.sin( reading.y * (Math.PI/180) ) * bubbleImage.prevX);

                bubbleImage.prevX = bubbleImage.x
                bubbleImage.prevY = bubbleImage.y@

  • I have a compass image and I have a bubble image embedded in it. Which is centered in the compass image initially. I would have to move the bubble based on the change in surface level. CHange in x,y,z axis when the device is moved. What do you suggest I do then?

  • I think you don't want to multiply by prevX and prevY...
    Obviously the centre of the circle is not at (0,0) from your snippet. I suggest you to use something like :

    @ // Define some local variables (i.e. such as centre is (0,0)
    localX = bubbleImage.prevX - centreX;
    localY = bubbleImage.prevY - centreY;
    // Modify the current position of the bubble
    bubbleImage.x = Math.cos( angle ) * localX - Math.sin( angle ) * localY + centreX;
    bubbleImage.y = Math.cos( angle ) * localY + Math.sin( angle ) * localX + centreY;
    // Update the bubble position
    bubbleImage.prevX = bubbleImage.x
    bubbleImage.prevY = bubbleImage.y

    But I realise now that I skipped the thing about the (x,y,z) rotation in a first reading. You then have to use a 3x3 matrix, and 3 angles have to be used. The problem is to define those three angles in a correct way, I suggest you have a look at "this wikipedia article": and especially "this part": Then I'm afraid you have to add the third dimension to your bubble position, and then make a projection on your 2D image.

  • This will work provided the entire device is rotated by theta. But the question I have is, I have the separate angles for x,y. It is rotated by two different angles. The qRotationSensor gives me the reading.x and reading.y which is the angle change with respect to the x and y plane.

    Currently I have, centrex,centreY(0,0)
    I have set prevx and prevy as initial x,y(centre of the bubble image) which is 180,320. And now angle here will refer to reading.x for cos and reading.y for sin?

    as in, will I have bubbleImage.x = Math.cos(reading.x)*localX - Math.sin(reading.x)*localY+centreX;
    and bubbleImage.y as Math.cos(reading.y)*localY + Math.sin(reading.y)*localX + centreY;

    Do we need centreY at all?It is always 0,0 right? Or I am going about this, totally the wrong way and should use shear mapping?

  • The code snippet I just gave you assumes a rotation in the (x,y) plane, which is actually a rotation around the z axis (since the z component remains constant).

    If your centreX and centreY are both zero, you don't really need them in your expressions, however I suggest you keep them in case you want to change the position of the circle centre.

    I think your problem is that you mix up the x and y of your screen and the x and y axis around which the rotations are preformed. I guess your screen (or display window) has width along the x axis and the y axis is the height. As long as your doing only 2D, there is only one allowed rotation, around the z axis. If you disagree imagine your bubble is drawn on a sheet of paper, which lies on your table. The table is horizontal, and we can define x and y axis on the table surface. Now, the only allowed rotation would be to rotate the sheet with an angle theta. If this is really what you are doing, then you need only one angle (in principle given by reading.z), and the formulas I gave you are correct. If you want to allow the sheet of paper not to be on the table any more (ie one corner would be above the table and the opposite one would be IN the table), then you need the full 3D rotation matrices and 3D coordinates.

  • BUt in this case, however I rotate the device, my reading.z is always zero.My centre is not 0,0. It is actually 180,320. If the initial Prevx and prev value is 0, the bubble image would be centered at -180,-320. Initially. Which would go out of the screen. if the initial prevx and prevy value is 180,320. The bubble image would be place at 0,0 initially.

  • What I am trying hard to implement, is actually similar to the bubble level apps,not the spirit level ones, for mobiles.

  • You mean something like "this":'s_eye_level_(level).jpg ?

    In this case you're right about the fact that you need two angles, however the coordinate of your bubble has to be in 3D, and then you just drop the z coordinate when you want to draw the bubble.

  • I tried this:
    @ var radianx = (Math.PI/180)*reading.x
    var radiany = (Math.PI/180)reading.y
    var tiltDirection = Math.atan2(radiany, radianx);
    var tiltMagnitude = Math.sqrt(radianx * radianx + radiany

                bubbleImage.x = 157 + (64*tiltMagnitude * (-Math.cos(tiltDirection )));
                bubbleImage.y = 297 + (64*tiltMagnitude * Math.sin(tiltDirection ));


    157,297 is my centre of the bubble. 110 is the radius of the outer circle, and 46 is the radius of the bubble. So 64(110-46), but does not seem to be accurate

  • I figured out. I need to use tiltDirection and tiltMagnitude in the same way as above. Just that image.y will be 297 - (tiltMagnitude...). Thanks a lot for your support on this!!

  • I'm glad you did it, you're welcome!

  • Thanks Johan!! I did it with the accelerometer instead of rotation sensor in this way:
    var radianx = accelerometer.reading.x
    var radiany =accelerometer.----reading.y
    var tiltDirection = Math.atan2(radiany, radianx);
    var tiltMagnitude = Math.sqrt(radianx * radianx + radiany*radiany);

    bubbleImage.x = bubbleImage.initX - (11tiltMagnitude * (Math.sin(tiltDirection )));
    bubbleImage.y = bubbleImage.initY + (11
    tiltMagnitude * (-Math.cos(tiltDirection )));@

    Now, how would I change the bubble sensitivity, that is, it should go the maximum displacement with a small angle change itself :)

Log in to reply