[Qt]QML地图-4

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtPositioning 5.15

Item {
id: root
width: 640
height: 480

property var baseCoordinate: { “latitude”: 36.35, “longitude”: 117.0 }
property var centerCoordinate: { “latitude”: 36.50, “longitude”: 117.2 } // 中心坐标
property int tileSize: 512
property int zoomLevel: 16
property string tileRoot: “file:///home/orangepi/Layer”
property var tilesCache: ({}) // 缓存瓦片对象

// 外部传入的旋转角度(单位:度)
property real markerAngle: 45

// 猴子标记
Image {
id: monkeyMarker
width: 30
height: 30
source: “qrc:/monkey.png”
z: 10
transformOrigin: Item.Center // 旋转中心在图片中点
rotation: root.markerAngle // 使用外部传入的角度
}

// 画红线
Canvas {
id: lineCanvas
anchors.fill: parent
z: 15
onPaint: {
var ctx = getContext(“2d”);
ctx.clearRect(0, 0, width, height);

ctx.lineWidth = 1;
ctx.strokeStyle = “red”;

var p1 = getPixelPos(root.baseCoordinate);
var p2 = getPixelPos(root.centerCoordinate);

ctx.beginPath();
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
}
}

Flickable {
id: flick
anchors.fill: parent
clip: true
interactive: true
contentWidth: 20000
contentHeight: 20000

Item {
id: tileContainer
width: flick.contentWidth
height: flick.contentHeight
}
}

// 经纬度 → 瓦片坐标
function coordToPixel(lat, lon) {
var zoom = root.zoomLevel;
var n = Math.pow(2, zoom);

var x = (lon + 180) / 360 * n;
var y = (1 – Math.log(Math.tan(lat * Math.PI / 180) +
1 / Math.cos(lat * Math.PI / 180)) / Math.PI) / 2 * n;
return { “x”: x, “y”: y };
}

// 转屏幕像素坐标
function getPixelPos(coord) {
var centerTile = coordToPixel(root.centerCoordinate.latitude, root.centerCoordinate.longitude);
var pointTile = coordToPixel(coord.latitude, coord.longitude);

var tilesX = Math.ceil(flick.width / root.tileSize) + 2;
var tilesY = Math.ceil(flick.height / root.tileSize) + 2;

var startX = Math.floor(centerTile.x – tilesX / 2);
var startY = Math.floor(centerTile.y – tilesY / 2);

var px = (pointTile.x – startX) * root.tileSize + tileContainer.x;
var py = (pointTile.y – startY) * root.tileSize + tileContainer.y;
return { “x”: px, “y”: py };
}

// 更新猴子位置(不再计算角度)
function updateMarkerPosition() {
var center = root.centerCoordinate;
var centerTile = coordToPixel(center.latitude, center.longitude);

var tilesX = Math.ceil(flick.width / root.tileSize) + 2;
var tilesY = Math.ceil(flick.height / root.tileSize) + 2;

var startX = Math.floor(centerTile.x – tilesX / 2);
var startY = Math.floor(centerTile.y – tilesY / 2);

// 计算中心点像素位置
var px = (centerTile.x – startX) * root.tileSize + tileContainer.x;
var py = (centerTile.y – startY) * root.tileSize + tileContainer.y;

monkeyMarker.x = px – monkeyMarker.width / 2;
monkeyMarker.y = py – monkeyMarker.height / 2;
}

// 更新瓦片
function updateVisibleTiles() {
if (!tileContainer || !root.centerCoordinate) return;

var zoom = root.zoomLevel;
var n = Math.pow(2, zoom);
var center = root.centerCoordinate;

var centerTile = coordToPixel(center.latitude, center.longitude);

var tilesX = Math.ceil(flick.width / root.tileSize) + 2;
var tilesY = Math.ceil(flick.height / root.tileSize) + 2;

var startX = Math.floor(centerTile.x – tilesX / 2);
var startY = Math.floor(centerTile.y – tilesY / 2);

var currentKeys = {};
for (var x = startX; x < startX + tilesX; x++) { for (var y = startY; y < startY + tilesY; y++) { var key = x + "_" + y; currentKeys[key] = true; var path = root.tileRoot + "/" + zoom + "/" + x + "/" + y + ".png"; if (!tilesCache[key]) { var tile = Qt.createQmlObject( 'import QtQuick 2.15; Image { width:' + root.tileSize + '; height:' + root.tileSize + '; source: "' + path + '"; fillMode: Image.PreserveAspectFit }', tileContainer ); tilesCache[key] = tile; } var tileObj = tilesCache[key]; tileObj.x = (x - startX) * root.tileSize; tileObj.y = (y - startY) * root.tileSize; } } // 删除多余瓦片 for (var key in tilesCache) { if (!currentKeys[key]) { tilesCache[key].destroy(); delete tilesCache[key]; } } // 平移 tileContainer,使中心瓦片对齐 var offsetX = (centerTile.x - startX) * root.tileSize - flick.width / 2; var offsetY = (centerTile.y - startY) * root.tileSize - flick.height / 2; tileContainer.x = -offsetX; tileContainer.y = -offsetY; updateMarkerPosition(); lineCanvas.requestPaint(); // 重新画红线 } Component.onCompleted: updateVisibleTiles() }

发表评论

邮箱地址不会被公开。 必填项已用*标注