Add iso view to snapshot

This commit is contained in:
c.lamboo 2023-10-20 23:14:58 +02:00
parent 1425dd01d5
commit fe4790fe06
2 changed files with 89 additions and 3 deletions

View file

@ -1,7 +1,9 @@
# Copyright (c) 2021 Ultimaker B.V. # Copyright (c) 2023 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import numpy import numpy
from typing import Optional
from PyQt6 import QtCore from PyQt6 import QtCore
from PyQt6.QtCore import QCoreApplication from PyQt6.QtCore import QCoreApplication
from PyQt6.QtGui import QImage from PyQt6.QtGui import QImage
@ -10,11 +12,13 @@ from UM.Logger import Logger
from cura.PreviewPass import PreviewPass from cura.PreviewPass import PreviewPass
from UM.Application import Application from UM.Application import Application
from UM.Math.AxisAlignedBox import AxisAlignedBox
from UM.Math.Matrix import Matrix from UM.Math.Matrix import Matrix
from UM.Math.Vector import Vector from UM.Math.Vector import Vector
from UM.Scene.Camera import Camera from UM.Scene.Camera import Camera
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNode import SceneNode
from UM.Qt.QtRenderer import QtRenderer
class Snapshot: class Snapshot:
@staticmethod @staticmethod
@ -32,6 +36,88 @@ class Snapshot:
return min_x, max_x, min_y, max_y return min_x, max_x, min_y, max_y
@staticmethod
def isometric_snapshot(width: int = 300, height: int = 300, *, root: Optional[SceneNode] = None) -> Optional[
QImage]:
"""Create an isometric snapshot of the scene."""
root = Application.getInstance().getController().getScene().getRoot() if root is None else root
# the direction the camera is looking at to create the isometric view
iso_view_dir = Vector(-1, -1, -1).normalized()
bounds = Snapshot.node_bounds(root)
if bounds is None:
Logger.log("w", "There appears to be nothing to render")
return None
camera = Camera("snapshot")
# find local x and y directional vectors of the camera
s = iso_view_dir.cross(Vector.Unit_Y).normalized()
u = s.cross(iso_view_dir).normalized()
# find extreme screen space coords of the scene
x_points = [p.dot(s) for p in bounds.points]
y_points = [p.dot(u) for p in bounds.points]
min_x = min(x_points)
max_x = max(x_points)
min_y = min(y_points)
max_y = max(y_points)
camera_width = max_x - min_x
camera_height = max_y - min_y
if camera_width == 0 or camera_height == 0:
Logger.log("w", "There appears to be nothing to render")
return None
# increase either width or height to match the aspect ratio of the image
if camera_width / camera_height > width / height:
camera_height = camera_width * height / width
else:
camera_width = camera_height * width / height
# Configure camera for isometric view
ortho_matrix = Matrix()
ortho_matrix.setOrtho(
-camera_width / 2,
camera_width / 2,
-camera_height / 2,
camera_height / 2,
-10000,
10000
)
camera.setPerspective(False)
camera.setProjectionMatrix(ortho_matrix)
camera.setPosition(bounds.center)
camera.lookAt(bounds.center + iso_view_dir)
# Render the scene
renderer = QtRenderer()
render_pass = PreviewPass(width, height)
renderer.setViewportSize(width, height)
renderer.setWindowSize(width, height)
render_pass.setCamera(camera)
renderer.addRenderPass(render_pass)
renderer.beginRendering()
renderer.render()
return render_pass.getOutput()
@staticmethod
def node_bounds(root_node: SceneNode) -> Optional[AxisAlignedBox]:
axis_aligned_box = None
for node in DepthFirstIterator(root_node):
if not getattr(node, "_outside_buildarea", False):
if node.callDecoration(
"isSliceable") and node.getMeshData() and node.isVisible() and not node.callDecoration(
"isNonThumbnailVisibleMesh"):
if axis_aligned_box is None:
axis_aligned_box = node.getBoundingBox()
else:
axis_aligned_box = axis_aligned_box + node.getBoundingBox()
return axis_aligned_box
@staticmethod @staticmethod
def snapshot(width = 300, height = 300): def snapshot(width = 300, height = 300):
"""Return a QImage of the scene """Return a QImage of the scene

View file

@ -61,7 +61,7 @@ class MakerbotWriter(MeshWriter):
Logger.warning("Can't create snapshot when renderer not initialized.") Logger.warning("Can't create snapshot when renderer not initialized.")
return return
try: try:
snapshot = Snapshot.snapshot(width, height) snapshot = Snapshot.isometric_snapshot(width, height)
except: except:
Logger.logException("w", "Failed to create snapshot image") Logger.logException("w", "Failed to create snapshot image")
return return