From 6be979c670635735379f1e893ff77c84c045a88d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Skowro=C5=84ski?= Date: Fri, 25 Oct 2024 17:23:10 +0200 Subject: [PATCH] Implemented CoR visualization --- cura/NavlibClient.py | 27 ++++++++++++- cura/Scene/OverlayNode.py | 68 +++++++++++++++++++++++++++++++++ resources/images/3dx_pivot.png | Bin 0 -> 1365 bytes 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 cura/Scene/OverlayNode.py create mode 100644 resources/images/3dx_pivot.png diff --git a/cura/NavlibClient.py b/cura/NavlibClient.py index 7f3994d631..7490377586 100644 --- a/cura/NavlibClient.py +++ b/cura/NavlibClient.py @@ -4,6 +4,7 @@ from UM.Math.Vector import Vector from UM.Math.AxisAlignedBox import AxisAlignedBox from cura.PickingPass import PickingPass from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator +from cura.Scene.OverlayNode import OverlayNode, SceneNode class NavlibClient(pynav.NavlibNavigationModel): @@ -15,6 +16,7 @@ class NavlibClient(pynav.NavlibNavigationModel): self._was_pick = False self._hit_selection_only = False self._picking_pass = None + self._pivot_node = OverlayNode(node=SceneNode(), image_path="resources/images/3dx_pivot.png", size=3.) def pick(self, x, y, check_selection = False, radius = 0.): @@ -218,6 +220,20 @@ class NavlibClient(pynav.NavlibNavigationModel): transformation = Matrix(data = matrix._matrix) self._scene.getActiveCamera().setTransformation(transformation) + active_camera = self._scene.getActiveCamera() + if active_camera.isPerspective(): + camera_position = active_camera.getWorldPosition() + dist = (camera_position - self._pivot_node.getWorldPosition()).length() + scale = dist/400 + if scale < 1.0: + scale = scale * scale + else: + view_width = active_camera.getViewportWidth() + current_size = view_width + (2 * active_camera.getZoomFactor() * view_width) + scale = current_size / view_width * 5 + + self._pivot_node.scale(scale) + def set_view_extents(self, extents: pynav.NavlibBox): view_width = self._scene.getActiveCamera().getViewportWidth() new_zoom = (extents._min._x + view_width / 2.) / - view_width @@ -235,4 +251,13 @@ class NavlibClient(pynav.NavlibNavigationModel): else: self._was_pick = False self._renderer.removeRenderPass(self._picking_pass) - \ No newline at end of file + + def set_pivot_position(self, position): + self._pivot_node._target_node.setPosition(position=Vector(position._x, position._y, position._z), transform_space = 3) + + def set_pivot_visible(self, visible): + if visible: + self._scene.getRoot().addChild(self._pivot_node) + else: + self._scene.getRoot().removeChild(self._pivot_node) + diff --git a/cura/Scene/OverlayNode.py b/cura/Scene/OverlayNode.py new file mode 100644 index 0000000000..c3be2d78af --- /dev/null +++ b/cura/Scene/OverlayNode.py @@ -0,0 +1,68 @@ +# Copyright (c) 2016 Ultimaker B.V. +# Cura is released under the terms of the AGPLv3 or higher. + +from UM.Scene.SceneNode import SceneNode +from UM.View.GL.OpenGL import OpenGL +from UM.Mesh.MeshBuilder import MeshBuilder # To create the overlay quad +from UM.Resources import Resources # To find shader locations +from UM.Math.Matrix import Matrix +from UM.Application import Application + +try: + from PyQt6.QtGui import QImage +except: + from PyQt5.QtGui import QImage + +class OverlayNode(SceneNode): + def __init__(self, node, image_path, parent=None, size=1.): + super().__init__(parent) + self._target_node = node + self.setCalculateBoundingBox(False) + + self._overlay_mesh = self._createOverlayQuad(size) + self._drawed_mesh = self._overlay_mesh + self._shader = None + self._scene = Application.getInstance().getController().getScene() + self._scale = 1. + self._image_path = image_path + + def scale(self, factor): + scale_matrix = Matrix() + scale_matrix.setByScaleFactor(factor) + self._drawed_mesh = self._overlay_mesh.getTransformed(scale_matrix) + + def _createOverlayQuad(self, size): + mb = MeshBuilder() + mb.addFaceByPoints(-size / 2, -size / 2, 0, -size / 2, size / 2, 0, size / 2, -size / 2, 0) + mb.addFaceByPoints(size / 2, size / 2, 0, -size / 2, size / 2, 0, size / 2, -size / 2, 0) + + # Set UV coordinates so a texture can be created + mb.setVertexUVCoordinates(0, 0, 1) + mb.setVertexUVCoordinates(1, 0, 0) + mb.setVertexUVCoordinates(4, 0, 0) + mb.setVertexUVCoordinates(2, 1, 1) + mb.setVertexUVCoordinates(5, 1, 1) + mb.setVertexUVCoordinates(3, 1, 0) + + return mb.build() + + def render(self, renderer): + + if not self._shader: + # We now misuse the platform shader, as it actually supports textures + self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "platform.shader")) + # Set the opacity to 0, so that the template is in full control. + self._shader.setUniformValue("u_opacity", 0) + self._texture = OpenGL.getInstance().createTexture() + texture_image = QImage(self._image_path) + self._texture.setImage(texture_image) + self._shader.setTexture(0, self._texture) + + node_position = self._target_node.getWorldPosition() + position_matrix = Matrix() + position_matrix.setByTranslation(node_position) + camera_orientation = self._scene.getActiveCamera().getOrientation().toMatrix() + + renderer.queueNode(self._scene.getRoot(), shader=self._shader, mesh=self._drawed_mesh.getTransformed(position_matrix.multiply(camera_orientation)), type=3) + + return True # This node does it's own rendering. diff --git a/resources/images/3dx_pivot.png b/resources/images/3dx_pivot.png new file mode 100644 index 0000000000000000000000000000000000000000..98525adc860781c9f85ec9b426c95367135aa3f7 GIT binary patch literal 1365 zcmeAS@N?(olHy`uVBq!ia0vp^JRmj)8<3o<+3y6TBuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFe_z-M3hAM`dB6B=jtVb)aX^@765fKFxc2v6eK2Rr0UTq__OB&@Hb09I0xZL0)vRD^GUf^&XRs)DJWfo`&anSp|tp`M|! ziMhGCj)IYap@F`Ek-njkuA#Y=v5}R5fdUjL0c|TvNwW%aaf8|g1^l#~=$>Fbx5 zm+O@q>*W`v>l<2HT7t|lGSUUA&@HaaD@m--%_~-hnc$LIoLrPyP?DLSrvNfBF)6>a z#8wIDQivCF3*g4)6+?pw7-0Gpi3R$GdIlgb!4&%X;#ZoR3s+rS5|oN?FIIz#Ln;eW z^@CE2^Gl18ff1Lc46>@g%DE^tu_V7JBtJg~7K#BG`6cH#s~$ri|gC;ZerU}`S{ChKf|!F&b= z#*>~djv*DdN+vmaOfHl-R{#He?)|9w-r0@0a%`@Oho?ABUs1}@w9B)d>9l7%-^Sp$ zBhhoGEbuw3U=Wc~+8MiRnju^11P&d=h)E}(1?^|G+V8)A?Z4Xl;XJWl4^&sqdtO^{ z|NDP;FVAGdKZ^hK?`b}i`sZ+G24}G0{J^cdI9s{i+%?x(zjgV|wz<6iYjrjoTQW8J z|M=^k@hNuU&ZpLOy2|=L+y3QM; ztnuk=e7R=Fvu8|gc1d3T^ziAU o_r-snpI_K~?!IislR8cVhFh!NN1pO!;{X+Op00i_>zopr01c@A@c;k- literal 0 HcmV?d00001