mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-08-06 10:18:42 +02:00
Some QML properties access exposed Python objects that may or may not be null upon their access. When these objects are accessed while null, QML issues "TypeError" warnings. These warnings have no functional impact as QML correctly handles trying to access null objects, but can spam the logs. This commit aims at fixing all these warnings by checking that the Python objects are not null before being accessed.
352 lines
12 KiB
QML
352 lines
12 KiB
QML
import QtQuick 2.7
|
|
import QtQuick.Controls 2.3
|
|
import QtQuick.Controls 1.4 as Controls1
|
|
import QtQuick.Layouts 1.3
|
|
import QtQml.Models 2.2
|
|
import QtQuick.Scene3D 2.0
|
|
import Qt3D.Core 2.1
|
|
import Qt3D.Render 2.1
|
|
import Qt3D.Extras 2.10
|
|
import Qt3D.Input 2.1 as Qt3DInput // to avoid clash with Controls2 Action
|
|
|
|
import MaterialIcons 2.2
|
|
|
|
import Controls 1.0
|
|
import Utils 1.0
|
|
|
|
|
|
FocusScope {
|
|
id: root
|
|
|
|
property int renderMode: 2
|
|
readonly property alias library: mediaLibrary
|
|
readonly property alias mainCamera: mainCamera
|
|
|
|
readonly property vector3d defaultCamPosition: Qt.vector3d(12.0, 10.0, -12.0)
|
|
readonly property vector3d defaultCamUpVector: Qt.vector3d(0.0, 1.0, 0.0)
|
|
readonly property vector3d defaultCamViewCenter: Qt.vector3d(0.0, 0.0, 0.0)
|
|
|
|
readonly property var viewpoint: _reconstruction ? _reconstruction.selectedViewpoint : null
|
|
readonly property bool doSyncViewpointCamera: Viewer3DSettings.syncViewpointCamera && (viewpoint && viewpoint.isReconstructed)
|
|
|
|
// functions
|
|
function resetCameraPosition() {
|
|
mainCamera.position = defaultCamPosition;
|
|
mainCamera.upVector = defaultCamUpVector;
|
|
mainCamera.viewCenter = defaultCamViewCenter;
|
|
}
|
|
|
|
function load(filepath) {
|
|
mediaLibrary.load(filepath);
|
|
}
|
|
|
|
/// View 'attribute' in the 3D Viewer. Media will be loaded if needed.
|
|
/// Returns whether the attribute can be visualized (matching type and extension).
|
|
function view(attribute) {
|
|
if( attribute.desc.type === "File"
|
|
&& Viewer3DSettings.supportedExtensions.indexOf(Filepath.extension(attribute.value)) > - 1 )
|
|
{
|
|
mediaLibrary.view(attribute);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Solo (i.e display only) the given attribute.
|
|
function solo(attribute) {
|
|
mediaLibrary.solo(mediaLibrary.find(attribute));
|
|
}
|
|
|
|
function clear() {
|
|
mediaLibrary.clear()
|
|
}
|
|
|
|
SystemPalette { id: activePalette }
|
|
|
|
|
|
Scene3D {
|
|
id: scene3D
|
|
anchors.fill: parent
|
|
cameraAspectRatioMode: Scene3D.AutomaticAspectRatio // vs. UserAspectRatio
|
|
hoverEnabled: true // if true, will trigger positionChanged events in attached MouseHandler
|
|
aspects: ["logic", "input"]
|
|
focus: true
|
|
|
|
|
|
Keys.onPressed: {
|
|
if (event.key == Qt.Key_F) {
|
|
resetCameraPosition();
|
|
}
|
|
else if(Qt.Key_1 <= event.key && event.key < Qt.Key_1 + Viewer3DSettings.renderModes.length)
|
|
{
|
|
Viewer3DSettings.renderMode = event.key - Qt.Key_1;
|
|
}
|
|
else {
|
|
event.accepted = false
|
|
}
|
|
}
|
|
|
|
Entity {
|
|
id: rootEntity
|
|
|
|
Camera {
|
|
id: mainCamera
|
|
projectionType: CameraLens.PerspectiveProjection
|
|
enabled: cameraSelector.camera == mainCamera
|
|
fieldOfView: 45
|
|
nearPlane : 0.01
|
|
farPlane : 10000.0
|
|
position: defaultCamPosition
|
|
upVector: defaultCamUpVector
|
|
viewCenter: defaultCamViewCenter
|
|
aspectRatio: width/height
|
|
|
|
Behavior on viewCenter {
|
|
Vector3dAnimation { duration: 250 }
|
|
}
|
|
Behavior on position {
|
|
Vector3dAnimation { duration: 250 }
|
|
}
|
|
|
|
// Scene light, attached to the camera
|
|
Entity {
|
|
components: [
|
|
PointLight {
|
|
color: "white"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
ViewpointCamera {
|
|
id: viewpointCamera
|
|
enabled: cameraSelector.camera === camera
|
|
viewpoint: root.viewpoint
|
|
camera.aspectRatio: width/height
|
|
}
|
|
|
|
TrackballGizmo {
|
|
beamRadius: 4.0/root.height
|
|
alpha: cameraController.moving ? 1.0 : 0.7
|
|
enabled: Viewer3DSettings.displayGizmo && cameraSelector.camera == mainCamera
|
|
xColor: Colors.red
|
|
yColor: Colors.green
|
|
zColor: Colors.blue
|
|
centerColor: Colors.sysPalette.highlight
|
|
transform: Transform {
|
|
translation: mainCamera.viewCenter
|
|
scale: 0.15 * mainCamera.viewCenter.minus(mainCamera.position).length()
|
|
}
|
|
}
|
|
|
|
DefaultCameraController {
|
|
id: cameraController
|
|
enabled: cameraSelector.camera == mainCamera
|
|
|
|
windowSize {
|
|
width: root.width
|
|
height: root.height
|
|
}
|
|
rotationSpeed: 16
|
|
trackballSize: 0.9
|
|
|
|
camera: mainCamera
|
|
focus: scene3D.activeFocus
|
|
onMousePressed: {
|
|
scene3D.forceActiveFocus()
|
|
if(mouse.button == Qt.LeftButton)
|
|
{
|
|
if(!doubleClickTimer.running)
|
|
doubleClickTimer.restart()
|
|
}
|
|
else
|
|
doubleClickTimer.stop()
|
|
}
|
|
onMouseReleased: {
|
|
if(moving)
|
|
return
|
|
if(!moved && mouse.button == Qt.RightButton)
|
|
{
|
|
contextMenu.popup()
|
|
}
|
|
}
|
|
|
|
// Manually handle double click to activate object picking
|
|
// for camera re-centering only during a short amount of time
|
|
Timer {
|
|
id: doubleClickTimer
|
|
running: false
|
|
interval: 300
|
|
}
|
|
}
|
|
|
|
components: [
|
|
RenderSettings {
|
|
pickingSettings.pickMethod: PickingSettings.PrimitivePicking // enables point/edge/triangle picking
|
|
pickingSettings.pickResultMode: PickingSettings.NearestPick
|
|
renderPolicy: RenderSettings.Always
|
|
|
|
activeFrameGraph: RenderSurfaceSelector {
|
|
// Use the whole viewport
|
|
Viewport {
|
|
normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
|
|
CameraSelector {
|
|
id: cameraSelector
|
|
camera: doSyncViewpointCamera ? viewpointCamera.camera : mainCamera
|
|
FrustumCulling {
|
|
ClearBuffers {
|
|
clearColor: "transparent"
|
|
buffers : ClearBuffers.ColorDepthBuffer
|
|
RenderStateSet {
|
|
renderStates: [
|
|
PointSize {
|
|
sizeMode: Viewer3DSettings.fixedPointSize ? PointSize.Fixed : PointSize.Programmable
|
|
value: Viewer3DSettings.pointSize
|
|
},
|
|
DepthTest { depthFunction: DepthTest.Less }
|
|
]
|
|
}
|
|
}
|
|
LayerFilter {
|
|
filterMode: LayerFilter.DiscardAnyMatchingLayers
|
|
layers: Layer {id: drawOnFront}
|
|
}
|
|
LayerFilter {
|
|
filterMode: LayerFilter.AcceptAnyMatchingLayers
|
|
layers: [drawOnFront]
|
|
RenderStateSet {
|
|
renderStates: DepthTest { depthFunction: DepthTest.GreaterOrEqual }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
Qt3DInput.InputSettings { }
|
|
]
|
|
|
|
MediaLibrary {
|
|
id: mediaLibrary
|
|
renderMode: Viewer3DSettings.renderMode
|
|
// Picking to set focus point (camera view center)
|
|
// Only activate it when a double click may happen or when the 'Control' key is pressed
|
|
pickingEnabled: cameraController.pickingActive || doubleClickTimer.running
|
|
camera: cameraSelector.camera
|
|
|
|
// Used for TransformGizmo in BoundingBox
|
|
sceneCameraController: cameraController
|
|
frontLayerComponent: drawOnFront
|
|
window: root
|
|
|
|
components: [
|
|
Transform {
|
|
id: transform
|
|
}
|
|
]
|
|
|
|
onPressed: {
|
|
if(pick.button == Qt.LeftButton)
|
|
{
|
|
mainCamera.viewCenter = pick.worldIntersection;
|
|
}
|
|
doubleClickTimer.stop();
|
|
}
|
|
|
|
}
|
|
Locator3D { enabled: Viewer3DSettings.displayOrigin }
|
|
Grid3D { enabled: Viewer3DSettings.displayGrid }
|
|
}
|
|
}
|
|
|
|
// Image overlay when navigating reconstructed cameras
|
|
Loader {
|
|
id: imageOverlayLoader
|
|
anchors.fill: parent
|
|
|
|
active: doSyncViewpointCamera
|
|
visible: Viewer3DSettings.showViewpointImageOverlay
|
|
|
|
sourceComponent: ImageOverlay {
|
|
id: imageOverlay
|
|
source: root.viewpoint.undistortedImageSource
|
|
imageRatio: root.viewpoint.orientedImageSize.width / root.viewpoint.orientedImageSize.height
|
|
uvCenterOffset: root.viewpoint.uvCenterOffset
|
|
showFrame: Viewer3DSettings.showViewpointImageFrame
|
|
imageOpacity: Viewer3DSettings.viewpointImageOverlayOpacity
|
|
}
|
|
}
|
|
|
|
// Media loading overlay
|
|
// (Scene3D is frozen while a media is being loaded)
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
visible: mediaLibrary.loading
|
|
color: Qt.darker(Colors.sysPalette.mid, 1.2)
|
|
opacity: 0.6
|
|
BusyIndicator {
|
|
anchors.centerIn: parent
|
|
running: parent.visible
|
|
}
|
|
}
|
|
|
|
FloatingPane {
|
|
visible: Viewer3DSettings.renderMode == 3
|
|
anchors.bottom: renderModesPanel.top
|
|
GridLayout {
|
|
columns: 2
|
|
rowSpacing: 0
|
|
|
|
RadioButton { text: "SHL File"; autoExclusive: true; checked: true }
|
|
TextField {
|
|
text: Viewer3DSettings.shlFile
|
|
selectByMouse: true
|
|
Layout.minimumWidth: 300
|
|
onEditingFinished: Viewer3DSettings.shlFile = text
|
|
}
|
|
|
|
RadioButton {
|
|
Layout.columnSpan: 2
|
|
autoExclusive: true
|
|
text: "Normals"
|
|
onCheckedChanged: Viewer3DSettings.displayNormals = checked
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// Rendering modes
|
|
FloatingPane {
|
|
id: renderModesPanel
|
|
anchors.bottom: parent.bottom
|
|
padding: 4
|
|
Row {
|
|
Repeater {
|
|
model: Viewer3DSettings.renderModes
|
|
|
|
delegate: MaterialToolButton {
|
|
text: modelData["icon"]
|
|
ToolTip.text: modelData["name"] + " (" + (index+1) + ")"
|
|
font.pointSize: 11
|
|
onClicked: Viewer3DSettings.renderMode = index
|
|
checked: Viewer3DSettings.renderMode === index
|
|
checkable: !checked // hack to disabled check on toggle
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Menu
|
|
Menu {
|
|
id: contextMenu
|
|
|
|
MenuItem {
|
|
text: "Fit All"
|
|
onTriggered: mainCamera.viewAll()
|
|
}
|
|
MenuItem {
|
|
text: "Reset View"
|
|
onTriggered: resetCameraPosition()
|
|
}
|
|
}
|
|
}
|