ansys-pyensight-core 0.10.6__tar.gz → 0.10.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ansys-pyensight-core might be problematic. Click here for more details.

Files changed (37) hide show
  1. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/PKG-INFO +1 -1
  2. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/pyproject.toml +2 -2
  3. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/views.py +235 -3
  4. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/LICENSE +0 -0
  5. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/README.rst +0 -0
  6. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/__init__.py +0 -0
  7. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/common.py +0 -0
  8. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/deep_pixel_view.html +0 -0
  9. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/dockerlauncher.py +0 -0
  10. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/dvs.py +0 -0
  11. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/enscontext.py +0 -0
  12. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/enshell_grpc.py +0 -0
  13. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/ensight_grpc.py +0 -0
  14. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/ensobj.py +0 -0
  15. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/launch_ensight.py +0 -0
  16. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/launcher.py +0 -0
  17. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/libuserd.py +0 -0
  18. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/listobj.py +0 -0
  19. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/locallauncher.py +0 -0
  20. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/py.typed +0 -0
  21. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/renderable.py +0 -0
  22. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/session.py +0 -0
  23. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/sgeo_poll.html +0 -0
  24. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/__init__.py +0 -0
  25. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/adr.py +0 -0
  26. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/dsg_server.py +0 -0
  27. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/export.py +0 -0
  28. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/omniverse.py +0 -0
  29. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/omniverse_cli.py +0 -0
  30. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/omniverse_dsg_server.py +0 -0
  31. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/omniverse_glb_server.py +0 -0
  32. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/parts.py +0 -0
  33. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/query.py +0 -0
  34. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/readers.py +0 -0
  35. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/resources/Materials/000_sky.exr +0 -0
  36. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/support.py +0 -0
  37. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.7}/src/ansys/pyensight/core/utils/variables.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ansys-pyensight-core
3
- Version: 0.10.6
3
+ Version: 0.10.7
4
4
  Summary: A python wrapper for Ansys EnSight
5
5
  Author-email: "ANSYS, Inc." <pyansys.core@ansys.com>
6
6
  Maintainer-email: "ANSYS, Inc." <pyansys.core@ansys.com>
@@ -6,7 +6,7 @@ build-backend = "flit_core.buildapi"
6
6
 
7
7
  [project]
8
8
  name = "ansys-pyensight-core"
9
- version = "0.10.6"
9
+ version = "0.10.7"
10
10
  description = "A python wrapper for Ansys EnSight"
11
11
  readme = "README.rst"
12
12
  requires-python = ">=3.10,<3.14"
@@ -161,7 +161,7 @@ recursive = true
161
161
  exclude = ["venv/*", "tests/*"]
162
162
 
163
163
  [tool.mypy]
164
- python_version = 3.10
164
+ python_version = "3.10"
165
165
  strict = false
166
166
  namespace_packages = true
167
167
  explicit_package_bases = true
@@ -18,9 +18,13 @@ Example to set an isometric view:
18
18
 
19
19
  """
20
20
 
21
+
21
22
  import math
23
+ from types import ModuleType
22
24
  from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Union
23
25
 
26
+ import numpy as np
27
+
24
28
  if TYPE_CHECKING:
25
29
  try:
26
30
  import ensight
@@ -28,14 +32,239 @@ if TYPE_CHECKING:
28
32
  from ansys.api.pyensight import ensight_api
29
33
 
30
34
 
35
+ VIEW_DICT = {
36
+ "x+": (1, 0, 0),
37
+ "x-": (-1, 0, 0),
38
+ "y+": (0, 1, 0),
39
+ "y-": (0, -1, 0),
40
+ "z+": (0, 0, 1),
41
+ "z-": (0, 0, -1),
42
+ "isometric": (1, 1, 1),
43
+ }
44
+
45
+
46
+ class _Simba:
47
+ """Hidden class to manage the interactor layer in simba"""
48
+
49
+ def __init__(self, ensight: Union["ensight_api.ensight", "ensight"], views: "Views"):
50
+ self.ensight = ensight
51
+ self.views = views
52
+ self._original_look_at = None
53
+ self._original_look_from = None
54
+ self._original_parallel_scale = None
55
+ self._original_view_angle = None
56
+ self._original_view_up = None
57
+
58
+ def _initialize_simba_view(self):
59
+ """Initialize the data for resetting the camera."""
60
+ vport = self.ensight.objs.core.VPORTS[0]
61
+ near_clip = vport.ZCLIPLIMITS[0]
62
+ view_angle = 2 * vport.PERSPECTIVEANGLE
63
+ self._original_parallel_scale = near_clip * math.tan(math.radians(view_angle) / 2)
64
+ self._original_view_angle = view_angle
65
+ (
66
+ self._original_look_from,
67
+ self._original_look_at,
68
+ self._original_view_up,
69
+ self._original_parallel_scale,
70
+ ) = self.compute_camera_from_ensight_opengl()
71
+ self.ensight.annotation.axis_global("off")
72
+ self.ensight.annotation.axis_local("off")
73
+ self.ensight.annotation.axis_model("off")
74
+
75
+ def get_center_of_rotation(self):
76
+ """Get EnSight center of rotation."""
77
+ return self.ensight.objs.core.VPORTS[0].TRANSFORMCENTER
78
+
79
+ def auto_scale(self):
80
+ """Auto scale view."""
81
+ self.ensight.view_transf.fit()
82
+ self._initialize_simba_view()
83
+ self.render()
84
+ return self.get_camera()
85
+
86
+ def set_view(self, value: str):
87
+ """Set the view."""
88
+ if value != "isometric":
89
+ new_value = value[1].upper() + value[0]
90
+ self.ensight.view_transf.view_recall(new_value)
91
+ else:
92
+ self.views.set_view_direction(
93
+ 1, 1, 1, perspective=self.ensight.objs.core.vports[0].PERSPECTIVE
94
+ )
95
+ self.auto_scale()
96
+ return self.get_camera()
97
+
98
+ def get_camera(self):
99
+ """Get EnSight camera settings in VTK format."""
100
+ vport = self.ensight.objs.core.VPORTS[0]
101
+ position, focal_point, view_up, parallel_scale = self.compute_camera_from_ensight_opengl()
102
+ vport = self.ensight.objs.core.VPORTS[0]
103
+ view_angle = 2 * vport.PERSPECTIVEANGLE
104
+ # The parameter parallel scale is the actual parallel scale only
105
+ # if the vport is in orthographic mode. If not, it is defined as the
106
+ # inverge of the tangent of half of the field of view
107
+ parallel_scale = parallel_scale
108
+ return {
109
+ "orthographic": not vport.PERSPECTIVE,
110
+ "view_up": view_up,
111
+ "position": position,
112
+ "focal_point": focal_point,
113
+ "view_angle": view_angle,
114
+ "parallel_scale": parallel_scale,
115
+ "reset_focal_point": self._original_look_at,
116
+ "reset_position": self._original_look_from,
117
+ "reset_parallel_scale": self._original_parallel_scale,
118
+ "reset_view_up": self._original_view_up,
119
+ "reset_view_angle": self._original_view_angle,
120
+ }
121
+
122
+ @staticmethod
123
+ def normalize(v):
124
+ """Normalize a numpy vector."""
125
+ norm = np.linalg.norm(v)
126
+ return v / norm if norm > 0 else v
127
+
128
+ @staticmethod
129
+ def rotation_matrix_to_quaternion(m):
130
+ """Convert a numpy rotation matrix to a quaternion."""
131
+ trace = np.trace(m)
132
+ if trace > 0:
133
+ s = 0.5 / np.sqrt(trace + 1.0)
134
+ w = 0.25 / s
135
+ x = (m[2, 1] - m[1, 2]) * s
136
+ y = (m[0, 2] - m[2, 0]) * s
137
+ z = (m[1, 0] - m[0, 1]) * s
138
+ else:
139
+ if m[0, 0] > m[1, 1] and m[0, 0] > m[2, 2]:
140
+ s = 2.0 * np.sqrt(1.0 + m[0, 0] - m[1, 1] - m[2, 2])
141
+ w = (m[2, 1] - m[1, 2]) / s
142
+ x = 0.25 * s
143
+ y = (m[0, 1] + m[1, 0]) / s
144
+ z = (m[0, 2] + m[2, 0]) / s
145
+ elif m[1, 1] > m[2, 2]:
146
+ s = 2.0 * np.sqrt(1.0 + m[1, 1] - m[0, 0] - m[2, 2])
147
+ w = (m[0, 2] - m[2, 0]) / s
148
+ x = (m[0, 1] + m[1, 0]) / s
149
+ y = 0.25 * s
150
+ z = (m[1, 2] + m[2, 1]) / s
151
+ else:
152
+ s = 2.0 * np.sqrt(1.0 + m[2, 2] - m[0, 0] - m[1, 1])
153
+ w = (m[1, 0] - m[0, 1]) / s
154
+ x = (m[0, 2] + m[2, 0]) / s
155
+ y = (m[1, 2] + m[2, 1]) / s
156
+ z = 0.25 * s
157
+ return np.array([x, y, z, w])
158
+
159
+ def compute_model_rotation_quaternion(self, camera_position, focal_point, view_up):
160
+ """Compute the quaternion from the input camera."""
161
+ forward = self.normalize(np.array(focal_point) - np.array(camera_position))
162
+ right = self.normalize(np.cross(forward, view_up))
163
+ true_up = np.cross(right, forward)
164
+ camera_rotation = np.vstack([right, true_up, -forward]).T
165
+ model_rotation = camera_rotation.T
166
+ quat = self.rotation_matrix_to_quaternion(model_rotation)
167
+ return quat
168
+
169
+ @staticmethod
170
+ def quaternion_multiply(q1, q2):
171
+ x1, y1, z1, w1 = q1
172
+ x2, y2, z2, w2 = q2
173
+ w = w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2
174
+ x = w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2
175
+ y = w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2
176
+ z = w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2
177
+ return np.array([x, y, z, w])
178
+
179
+ def quaternion_to_euler(self, q):
180
+ q = self.normalize(q)
181
+ x, y, z, w = q
182
+ sinr_cosp = 2 * (w * x + y * z)
183
+ cosr_cosp = 1 - 2 * (x * x + y * y)
184
+ roll = np.arctan2(sinr_cosp, cosr_cosp)
185
+
186
+ sinp = 2 * (w * y - z * x)
187
+ if abs(sinp) >= 1:
188
+ pitch = np.pi / 2 * np.sign(sinp)
189
+ else:
190
+ pitch = np.arcsin(sinp)
191
+ siny_cosp = 2 * (w * z + x * y)
192
+ cosy_cosp = 1 - 2 * (y * y + z * z)
193
+ yaw = np.arctan2(siny_cosp, cosy_cosp)
194
+
195
+ return np.degrees([roll, pitch, yaw])
196
+
197
+ def compute_camera_from_ensight_opengl(self):
198
+ """Simulate a rotating camera using the current quaternion."""
199
+ if isinstance(self.ensight, ModuleType):
200
+ data = self.ensight.objs.core.VPORTS[0].simba_camera()
201
+ else:
202
+ data = self.ensight._session.cmd("ensight.objs.core.VPORTS[0].simba_camera())")
203
+ camera_position = [data[0], data[1], data[2]]
204
+ focal_point = [data[3], data[4], data[5]]
205
+ view_up = [data[6], data[7], data[8]]
206
+ parallel_scale = 1 / data[9]
207
+ return camera_position, focal_point, self.views._normalize_vector(view_up), parallel_scale
208
+
209
+ def set_camera(
210
+ self, orthographic, view_up=None, position=None, focal_point=None, view_angle=None
211
+ ):
212
+ """Set the EnSight camera settings from the VTK input."""
213
+ perspective = "OFF" if orthographic else "ON"
214
+ if orthographic:
215
+ self.ensight.view.perspective(perspective)
216
+ vport = self.ensight.objs.core.VPORTS[0]
217
+ if view_angle:
218
+ vport.PERSPECTIVEANGLE = view_angle / 2
219
+
220
+ if view_up and position and focal_point:
221
+ q_current = self.normalize(np.array(vport.ROTATION.copy()))
222
+ q_target = self.normalize(
223
+ self.compute_model_rotation_quaternion(position, focal_point, view_up)
224
+ )
225
+ q_relative = self.quaternion_multiply(
226
+ q_target, np.array([-q_current[0], -q_current[1], -q_current[2], q_current[3]])
227
+ )
228
+ angles = self.quaternion_to_euler(q_relative)
229
+ self.ensight.view_transf.rotate(*angles)
230
+ self.render()
231
+
232
+ def set_perspective(self, value):
233
+ vport = self.ensight.objs.core.VPORTS[0]
234
+ self.ensight.view.perspective(value)
235
+ vport.PERSPECTIVE = value == "ON"
236
+ self.ensight.view_transf.zoom(1)
237
+ self.ensight.view_transf.rotate(0, 0, 0)
238
+ self.render()
239
+ return self.get_camera()
240
+
241
+ def screen_to_world(self, mousex, mousey, invert_y=False, set_center=False):
242
+ mousex = int(mousex)
243
+ mousey = int(mousey)
244
+ if isinstance(self.ensight, ModuleType):
245
+ model_point = self.ensight.objs.core.VPORTS[0].screen_to_coords(
246
+ mousex, mousey, invert_y, set_center
247
+ )
248
+ else:
249
+ model_point = self.ensight._session.cmd(
250
+ f"ensight.objs.core.VPORTS[0].screen_to_coords({mousex}, {mousey}, {invert_y}, {set_center})"
251
+ )
252
+ self.render()
253
+ return {"model_point": model_point, "camera": self.get_camera()}
254
+
255
+ def render(self):
256
+ self.ensight.render()
257
+ self.ensight.refresh(1)
258
+
259
+
31
260
  class Views:
32
261
  """Controls the view in the current EnSight ``Session`` instance."""
33
262
 
34
263
  def __init__(self, ensight: Union["ensight_api.ensight", "ensight"]):
35
264
  self.ensight = ensight
36
265
  self._views_dict: Dict[str, Tuple[int, List[float]]] = {}
266
+ self._simba = _Simba(ensight, self)
37
267
 
38
- # Utilities
39
268
  @staticmethod
40
269
  def _normalize_vector(direction: List[float]) -> List[float]:
41
270
  """Return the normalized input (3D) vector.
@@ -295,14 +524,17 @@ class Views:
295
524
  vportindex : int, optional
296
525
  Viewport to set the view direction for. The default is ``0``.
297
526
  """
298
- self.ensight.view.perspective("OFF")
299
- direction = [xdir, ydir, zdir]
300
527
  vport = self.ensight.objs.core.VPORTS[vportindex]
528
+ if not perspective:
529
+ self.ensight.view.perspective("OFF")
530
+ vport.PERSPECTIVE = False
531
+ direction = [xdir, ydir, zdir]
301
532
  rots = vport.ROTATION.copy()
302
533
  rots[0:4] = self._convert_view_direction_to_quaternion(direction, up_axis=up_axis)
303
534
  vport.ROTATION = rots
304
535
  if perspective:
305
536
  self.ensight.view.perspective("ON")
537
+ vport.PERSPECTIVE = True
306
538
  self.save_current_view(name=name, vportindex=vportindex)
307
539
 
308
540
  def save_current_view(