Merge pull request #20249 from Ultimaker/CURA-12404_add-exeption-when-lib-is-missing

CURA-12404 Define dummy 3DConnexion interface in case module is not available
This commit is contained in:
HellAholic 2025-02-13 11:08:09 +01:00 committed by GitHub
commit 159098070a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 82 additions and 57 deletions

View File

@ -567,17 +567,6 @@ pip_requirements_core:
hashes:
- sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5
- sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413
pynavlib:
version: "0.9.4"
hashes:
- sha256:567efd0af97f9014326898b209eea94d9f5cc58e9f589ccf8354584568fcb87d
- sha256:fdd5ab5b6e0a2c9bbcebb154ac7303daf845865a1649be04e1bd8e8e5889401f
- sha256:f0d7ce426e816788aa96b419fd7da263eafb99aca46ce3b6e5dbaf2bbf6b614a
- sha256:493c4b3cacc939b021a694d99723106dbd7ee5515ad4dfc1c7fc8219ef20cf3a
- sha256:33962a322033a78db05a8c2cc3d59e057fbea5b04879c3c54e2fe3041d691a12
- sha256:332831553a70be05fe58c43a08109b42970cfedc6086ffb4306859142a0e9210
- sha256:d06d94b1dee4ba024b4a121869e572f571673a3b8c15b4055f52236d43c19a02
- sha256:9173f61ad83172c306b92bbe38f949889c158cd6dfdc924db01f257a437bf2a6
Windows:
twisted-iocpsupport:
@ -600,6 +589,22 @@ pip_requirements_core:
hashes:
- sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8
- sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755
pynavlib:
version: "0.9.4"
hashes:
- sha256:fdd5ab5b6e0a2c9bbcebb154ac7303daf845865a1649be04e1bd8e8e5889401f
- sha256:493c4b3cacc939b021a694d99723106dbd7ee5515ad4dfc1c7fc8219ef20cf3a
- sha256:332831553a70be05fe58c43a08109b42970cfedc6086ffb4306859142a0e9210
- sha256:9173f61ad83172c306b92bbe38f949889c158cd6dfdc924db01f257a437bf2a6
Macos:
pynavlib:
version: "0.9.4"
hashes:
- sha256:567efd0af97f9014326898b209eea94d9f5cc58e9f589ccf8354584568fcb87d
- sha256:f0d7ce426e816788aa96b419fd7da263eafb99aca46ce3b6e5dbaf2bbf6b614a
- sha256:33962a322033a78db05a8c2cc3d59e057fbea5b04879c3c54e2fe3041d691a12
- sha256:d06d94b1dee4ba024b4a121869e572f571673a3b8c15b4055f52236d43c19a02
pip_requirements_dev:
any_os:

View File

@ -1,4 +1,3 @@
import pynavlib.pynavlib_interface as pynav
from UM.Math.Matrix import Matrix
from UM.Math.Vector import Vector
from UM.Math.AxisAlignedBox import AxisAlignedBox
@ -6,10 +5,22 @@ from cura.PickingPass import PickingPass
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from cura.Scene.OverlayNode import OverlayNode, SceneNode
from UM.Resources import Resources
from UM.Logger import Logger
class NavlibClient(pynav.NavlibNavigationModel):
try:
import pynavlib.pynavlib_interface as pynav
parent_class = pynav.NavlibNavigationModel
except BaseException as exception:
Logger.warning(f"Unable to load 3DConnexion library: {exception}")
pynav = None
parent_class = object
class NavlibClient(parent_class):
def __init__(self, scene, renderer) -> None:
if not pynav:
return
super().__init__(False, pynav.NavlibOptions.RowMajorOrder)
self._scene = scene
self._renderer = renderer
@ -19,6 +30,14 @@ class NavlibClient(pynav.NavlibNavigationModel):
self._picking_pass = None
self._pivot_node = OverlayNode(node=SceneNode(), image_path=Resources.getPath(Resources.Images, "cor.png"), size=2.5)
def put_profile_hint(self, hint) -> None:
if pynav:
super().put_profile_hint(hint)
def enable_navigation(self, enabled) -> None:
if pynav:
super().enable_navigation(enabled)
def pick(self, x, y, check_selection = False, radius = 0.):
if self._picking_pass is None or radius < 0.:
@ -39,7 +58,7 @@ class NavlibClient(pynav.NavlibNavigationModel):
coord_x = (x - radius) + i * step
coord_y = (y - radius) + j * step
picked_depth = self._picking_pass.getPickedDepth(coord_x, coord_y)
max_depth = 16777.215
@ -62,10 +81,10 @@ class NavlibClient(pynav.NavlibNavigationModel):
if picked_depth < min_depth:
min_depth = picked_depth
result_position = self._picking_pass.getPickedPosition(coord_x, coord_y)
return result_position
def get_pointer_position(self)->pynav.NavlibVector:
def get_pointer_position(self) -> "pynav.NavlibVector":
from UM.Qt.QtApplication import QtApplication
main_window = QtApplication.getInstance().getMainWindow()
@ -77,7 +96,7 @@ class NavlibClient(pynav.NavlibNavigationModel):
self._was_pick = True
from cura.Utils.Threading import call_on_qt_thread
wrapped_pick = call_on_qt_thread(self.pick)
self._pointer_pick = wrapped_pick(x_n, y_n)
return pynav.NavlibVector(0., 0., 0.)
@ -87,7 +106,7 @@ class NavlibClient(pynav.NavlibNavigationModel):
return pynav.NavlibVector(pointer_position.x, pointer_position.y, pointer_position.z)
def get_view_extents(self)->pynav.NavlibBox:
def get_view_extents(self) -> "pynav.NavlibBox":
view_width = self._scene.getActiveCamera().getViewportWidth()
view_height = self._scene.getActiveCamera().getViewportHeight()
@ -99,18 +118,18 @@ class NavlibClient(pynav.NavlibNavigationModel):
return pynav.NavlibBox(pt_min, pt_max)
def get_view_frustum(self)->pynav.NavlibFrustum:
def get_view_frustum(self) -> "pynav.NavlibFrustum":
projection_matrix = self._scene.getActiveCamera().getProjectionMatrix()
half_height = 2. / projection_matrix.getData()[1,1]
half_width = half_height * (projection_matrix.getData()[1,1] / projection_matrix.getData()[0,0])
return pynav.NavlibFrustum(-half_width, half_width, -half_height, half_height, 1., 5000.)
def get_is_view_perspective(self)->bool:
def get_is_view_perspective(self) -> bool:
return self._scene.getActiveCamera().isPerspective()
def get_selection_extents(self)->pynav.NavlibBox:
def get_selection_extents(self) -> "pynav.NavlibBox":
from UM.Scene.Selection import Selection
bounding_box = Selection.getBoundingBox()
@ -120,33 +139,33 @@ class NavlibClient(pynav.NavlibNavigationModel):
pt_max = pynav.NavlibVector(bounding_box.maximum.x, bounding_box.maximum.y, bounding_box.maximum.z)
return pynav.NavlibBox(pt_min, pt_max)
def get_selection_transform(self)->pynav.NavlibMatrix:
def get_selection_transform(self) -> "pynav.NavlibMatrix":
return pynav.NavlibMatrix()
def get_is_selection_empty(self)->bool:
def get_is_selection_empty(self) -> bool:
from UM.Scene.Selection import Selection
return not Selection.hasSelection()
def get_pivot_visible(self)->bool:
def get_pivot_visible(self) -> bool:
return False
def get_camera_matrix(self)->pynav.NavlibMatrix:
def get_camera_matrix(self) -> "pynav.NavlibMatrix":
transformation = self._scene.getActiveCamera().getLocalTransformation()
return pynav.NavlibMatrix([[transformation.at(0, 0), transformation.at(0, 1), transformation.at(0, 2), transformation.at(0, 3)],
[transformation.at(1, 0), transformation.at(1, 1), transformation.at(1, 2), transformation.at(1, 3)],
[transformation.at(2, 0), transformation.at(2, 1), transformation.at(2, 2), transformation.at(2, 3)],
[transformation.at(3, 0), transformation.at(3, 1), transformation.at(3, 2), transformation.at(3, 3)]])
def get_coordinate_system(self)->pynav.NavlibMatrix:
def get_coordinate_system(self) -> "pynav.NavlibMatrix":
return pynav.NavlibMatrix()
def get_front_view(self)->pynav.NavlibMatrix:
def get_front_view(self) -> "pynav.NavlibMatrix":
return pynav.NavlibMatrix()
def get_model_extents(self)->pynav.NavlibBox:
def get_model_extents(self) -> "pynav.NavlibBox":
result_bbox = AxisAlignedBox()
build_volume_bbox = None
@ -166,12 +185,12 @@ class NavlibClient(pynav.NavlibNavigationModel):
self._scene_center = result_bbox.center
self._scene_radius = (result_bbox.maximum - self._scene_center).length()
return pynav.NavlibBox(pt_min, pt_max)
def get_pivot_position(self)->pynav.NavlibVector:
def get_pivot_position(self) -> "pynav.NavlibVector":
return pynav.NavlibVector()
def get_hit_look_at(self)->pynav.NavlibVector:
def get_hit_look_at(self) -> "pynav.NavlibVector":
if self._was_pick and self._pointer_pick is not None:
return pynav.NavlibVector(self._pointer_pick.x, self._pointer_pick.y, self._pointer_pick.z)
elif self._was_pick and self._pointer_pick is None:
@ -183,21 +202,21 @@ class NavlibClient(pynav.NavlibNavigationModel):
if picked_position is not None:
return pynav.NavlibVector(picked_position.x, picked_position.y, picked_position.z)
def get_units_to_meters(self)->float:
def get_units_to_meters(self) -> float:
return 0.05
def is_user_pivot(self)->bool:
def is_user_pivot(self) -> bool:
return False
def set_camera_matrix(self, matrix : pynav.NavlibMatrix):
def set_camera_matrix(self, matrix : "pynav.NavlibMatrix"):
# !!!!!!
# Hit testing in Orthographic view is not reliable
# Picking starts in camera position, not on near plane
# which results in wrong depth values (visible geometry
# cannot be picked properly) - Workaround needed (camera position offset)
# !!!!!!
# !!!!!!
if not self.get_is_view_perspective():
affine = matrix._matrix
direction = Vector(-affine[0][2], -affine[1][2], -affine[2][2])
@ -216,7 +235,7 @@ class NavlibClient(pynav.NavlibNavigationModel):
matrix._matrix[0][3] = matrix._matrix[0][3] - offset * direction.x
matrix._matrix[1][3] = matrix._matrix[1][3] - offset * direction.y
matrix._matrix[2][3] = matrix._matrix[2][3] - offset * direction.z
matrix._matrix[2][3] = matrix._matrix[2][3] - offset * direction.z
transformation = Matrix(data = matrix._matrix)
self._scene.getActiveCamera().setTransformation(transformation)
@ -233,7 +252,7 @@ class NavlibClient(pynav.NavlibNavigationModel):
self._pivot_node.scale(scale)
def set_view_extents(self, extents: pynav.NavlibBox):
def set_view_extents(self, extents: "pynav.NavlibBox"):
view_width = self._scene.getActiveCamera().getViewportWidth()
new_zoom = (extents._min._x + view_width / 2.) / - view_width
self._scene.getActiveCamera().setZoomFactor(new_zoom)
@ -250,13 +269,12 @@ class NavlibClient(pynav.NavlibNavigationModel):
else:
self._was_pick = False
self._renderer.removeRenderPass(self._picking_pass)
def set_pivot_position(self, position):
self._pivot_node._target_node.setPosition(position=Vector(position._x, position._y, position._z), transform_space = SceneNode.TransformSpace.World)
def set_pivot_visible(self, visible):
if visible:
self._scene.getRoot().addChild(self._pivot_node)
else:
self._scene.getRoot().removeChild(self._pivot_node)

View File

@ -3,7 +3,7 @@ import argparse
from pathlib import Path
def get_package_wheel_hashes(package, version):
def get_package_wheel_hashes(package, version, os):
url = f"https://pypi.org/pypi/{package}/{version}/json"
data = requests.get(url).json()
@ -12,7 +12,8 @@ def get_package_wheel_hashes(package, version):
print(f" hashes:")
for url in data["urls"]:
print(f" - sha256:{url['digests']['sha256']}")
if os is None or os in url["filename"]:
print(f" - sha256:{url['digests']['sha256']}")
if __name__ == "__main__":
@ -20,5 +21,6 @@ if __name__ == "__main__":
description="Display the hashes of the wheel files to be inserted in pip_requirements")
parser.add_argument("package", type=Path, help="Name of the target package")
parser.add_argument("version", type=Path, help="Version of the target package")
parser.add_argument('--os', type=str, help='Specific package OS', choices=['win', 'macosx', 'manylinux', 'musllinux'])
args = parser.parse_args()
get_package_wheel_hashes(args.package, args.version)
get_package_wheel_hashes(args.package, args.version, args.os)