Robot Monitor
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
import QtQuick3D
import QtQuick3D.Helpers
import QtRos2.NavMsgs
Node {
id: gridNode
property occupancyGrid grid: ({})
property bool applyOriginTransform: true // Set to false when parent handles transform
property alias scheme: gridPalette.scheme
readonly property real resolution: grid.info.resolution
readonly property real width: grid.info.width
readonly property real height: grid.info.height
readonly property real realWidth: width * resolution
readonly property real realHeight: height * resolution
position: GeometryHeleper.toVector3d(grid.info.origin.position)
rotation: GeometryHeleper.toQuaternion(grid.info.origin.orientation)
Model {
position: Qt.vector3d(gridNode.realWidth / 2,
gridNode.realHeight / 2, 0)
// In Qt 6.9+ we could use:
// PlaneGeometry {
// id: planeGeometry
// width: gridNode.realWidth
// height: gridNode.realHeight
// plane: PlaneGeometry.XY
// mirrored: true
// }
geometry: ProceduralMesh {
property real w2: gridNode.realWidth / 2
property real h2: gridNode.realHeight / 2
positions: [Qt.vector3d(-w2, -h2, 0), // Index 0: Bottom Left
Qt.vector3d(w2, -h2, 0), // Index 1: Bottom Right
Qt.vector3d(w2, h2, 0), // Index 2: Top Right
Qt.vector3d(-w2, h2, 0) // Index 3: Top Left
]
// Vertical Flip (mirrored: true)
// Standard: (0,0), (1,0), (1,1), (0,1)
// Vertically Mirrored: (0,1), (1,1), (1,0), (0,0)
uv0s: [Qt.vector2d(0, 1), // Bottom Left (V is now 1)
Qt.vector2d(1, 1), // Bottom Right (V is now 1)
Qt.vector2d(1, 0), // Top Right (V is now 0)
Qt.vector2d(0, 0) // Top Left (V is now 0)
]
indexes: [0, 1, 2, 0, 2, 3]
normals: [Qt.vector3d(0, 0, 1), Qt.vector3d(0, 0, 1), Qt.vector3d(
0, 0, 1), Qt.vector3d(0, 0, 1)]
}
materials: CustomMaterial {
shadingMode: CustomMaterial.Unshaded
cullMode: Material.NoCulling
sourceBlend: CustomMaterial.SrcAlpha
destinationBlend: CustomMaterial.OneMinusSrcAlpha
// 1. Raw Data Input
property TextureInput indexMap: TextureInput {
texture: Texture {
minFilter: Texture.Nearest // Vital for crisp pixels
magFilter: Texture.Nearest
tilingModeHorizontal: Texture.ClampToEdge
tilingModeVertical: Texture.ClampToEdge
textureData: ProceduralTextureData {
textureData: gridNode.grid.data
width: gridNode.grid.info.width
height: gridNode.grid.info.height
format: ProceduralTextureData.R8
}
}
}
// 2. Palette Input (Shared)
property TextureInput paletteMap: TextureInput {
texture: Texture {
textureData: GridPalette {
id: gridPalette
}
minFilter: Texture.Nearest
magFilter: Texture.Nearest
tilingModeHorizontal: Texture.ClampToEdge
tilingModeVertical: Texture.ClampToEdge
}
}
property real opacity: gridNode.opacity
fragmentShader: "shaders/IndexedGrid.frag"
vertexShader: "shaders/IndexedGrid.vert"
}
}
}