Qt QML MapItem Rotation issue

203 views Asked by At

I have a QML OSM map and a MapQuickItem with Text source item:

MapQuickItem {
            property alias rulerRotationAngle: rulerRotation.angle
            id: rulerTextMapItem
            visible: false
            width: 2
            height: 2
            transform: Rotation {
                id: rulerRotation
                origin.x: rulerText.width/2;
                origin.y: rulerText.height/2;
                angle: 0
            }
            anchorPoint.x: rulerText.width/2
            anchorPoint.y: rulerText.height/2
            z:5
            sourceItem: Text {
                id: rulerText;               horizontalAlignment: Text.AlignHCenter
                verticalAlignment: Text.AlignVCenter
                color: Material.color(Material.Amber, Material.Shade100)
                text: "0.0 km";
            }
        }

I also have two points (QtPositioning.coordinate) and I want the text to rotate depending on the angle of the straight line (MapPolyLine) drawn between those points:

function drawRuler()
    {
        rulerLine.path = [];
        rulerLine.addCoordinate(r_firstpoint);
        rulerLine.addCoordinate(r_secondpoint);
        rulerTextMapItem.visible = true;
        rulerTextMapItem.coordinate = QtPositioning.coordinate((r_firstpoint.latitude+r_secondpoint.latitude)/2, (r_firstpoint.longitude+r_secondpoint.longitude)/2);
        var atan = Math.atan2(r_secondpoint.longitude-r_firstpoint.longitude, r_secondpoint.latitude-r_firstpoint.latitude);
        var angle = ((atan*180)/Math.PI); //used by another MapItem
        var textAngle = angle+270;
        if(textAngle>90 & textAngle<270) { textAngle+=180 }
        if(angle>90 & angle<270) { angle +=180 }
        rulerTextMapItem.rulerRotationAngle = textAngle;
    }

However, text rotates correctly only at angles that are multiples of 90 degrees. At an angle of 45 degrees, the text deviates from the mappolyline by about 10-20 degrees. I have no clue why it happens and appreciate any help.

Tried to move transform.origin of MapQuickItem - angle difference only gets bigger. Tried to use Math.Atan instead of Math.Atan2 - no difference.

1

There are 1 answers

0
Stephen Quan On

The main issue is this line and the order of inputs:

var atan = Math.atan2(
    r_secondpoint.longitude-r_firstpoint.longitude,
    r_secondpoint.latitude-r_firstpoint.latitude);

latitude should come before longitude, i.e.

var atan = Math.atan2(
    r_secondpoint.latitude-r_firstpoint.latitude,
    r_secondpoint.longitude-r_firstpoint.longitude);

Generally speaking, to use Math.atan2() to convert to an angle, you need to use one of the following patterns:

let radians = Math.atan2(vectorY, vectorX)
let degrees = Math.atan2(vectorY, vectorX) * 180 / Math.PI

Also over large angles, you definitely should use project your angular coordinates to a flat projection, e.g. QtPositioning.coordToMercator. (This point was raised in one of the earlier comments).

For very small angles you can get away with it because the earth can be approximated to a flat earth directly from angular coordinates, but, as the area goes, this fact quickly disappears.

The following code demonstrates Math.atan2() and how it must work with (vectorY, vectorX) inputs. It has two draggable squares and you watch that the text will always follow the direction of the blue line no matter where the squares are:

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Shapes
Page {
    id: page

    width: 200; height: 200

    property int startX: rect1.x + rect1.width /   2
    property int startY: rect1.y + rect1.height / 2
    property int finishX: rect2.x + rect2.width /   2
    property int finishY: rect2.y + rect2.height / 2

    Rectangle {
        id: rect1
        x: 40; y: 40
        width: 40; height: 40
        color: "red"
        Drag.active: dragArea.drag.active
        Drag.hotSpot.x: 20
        Drag.hotSpot.y: 20
        MouseArea {
            id: dragArea
            anchors.fill: parent
            drag.target: parent
        }
    }

    Rectangle {
        id: rect2
        x: 400; y: 250
        width: 40; height: 40
        color: "red"
        Drag.active: dragArea2.drag.active
        Drag.hotSpot.x: 20
        Drag.hotSpot.y: 20
        MouseArea {
            id: dragArea2
            anchors.fill: parent
            drag.target: parent
        }
    }

    Shape {
        id: shape
        
        ShapePath {
            strokeWidth: 4
            strokeColor: "blue"
            startX: page.startX
            startY: page.startY

            PathLine {
                x: page.finishX
                y: page.finishY
            }
        }
    }

    Item {
        x: (startX + finishX) / 2
        y: (startY + finishY) / 2
        rotation: Math.atan2(finishY - startY, finishX - startX) * 180 / Math.PI
        Frame {
            anchors.centerIn: parent
            background: Rectangle {
                border.color: "black"
            }
            Text {
                text: "Hello World"
            }
        }
    }
}

You can Try it Online!