ansys-pyensight-core 0.10.6__tar.gz → 0.10.8__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.8}/PKG-INFO +3 -3
  2. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/pyproject.toml +4 -4
  3. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/common.py +1 -1
  4. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/dvs.py +3 -1
  5. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/enshell_grpc.py +1 -1
  6. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/libuserd.py +2 -2
  7. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/session.py +2 -2
  8. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/utils/omniverse.py +1 -1
  9. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/utils/views.py +239 -3
  10. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/LICENSE +0 -0
  11. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/README.rst +0 -0
  12. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/__init__.py +0 -0
  13. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/deep_pixel_view.html +0 -0
  14. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/dockerlauncher.py +0 -0
  15. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/enscontext.py +0 -0
  16. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/ensight_grpc.py +0 -0
  17. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/ensobj.py +0 -0
  18. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/launch_ensight.py +0 -0
  19. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/launcher.py +0 -0
  20. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/listobj.py +0 -0
  21. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/locallauncher.py +0 -0
  22. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/py.typed +0 -0
  23. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/renderable.py +0 -0
  24. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/sgeo_poll.html +0 -0
  25. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/utils/__init__.py +0 -0
  26. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/utils/adr.py +0 -0
  27. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/utils/dsg_server.py +0 -0
  28. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/utils/export.py +0 -0
  29. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/utils/omniverse_cli.py +0 -0
  30. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/utils/omniverse_dsg_server.py +0 -0
  31. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/utils/omniverse_glb_server.py +0 -0
  32. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/utils/parts.py +0 -0
  33. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/utils/query.py +0 -0
  34. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/utils/readers.py +0 -0
  35. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/utils/resources/Materials/000_sky.exr +0 -0
  36. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/src/ansys/pyensight/core/utils/support.py +0 -0
  37. {ansys_pyensight_core-0.10.6 → ansys_pyensight_core-0.10.8}/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.8
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>
@@ -17,10 +17,10 @@ Classifier: Programming Language :: Python :: 3.12
17
17
  Classifier: Programming Language :: Python :: 3.13
18
18
  License-File: LICENSE
19
19
  Requires-Dist: importlib-metadata>=4.0; python_version<='3.8'
20
- Requires-Dist: ansys-api-pyensight==0.4.8
20
+ Requires-Dist: ansys-api-pyensight==0.4.9
21
21
  Requires-Dist: requests>=2.28.2
22
22
  Requires-Dist: docker>=6.1.0
23
- Requires-Dist: urllib3<2.4.0
23
+ Requires-Dist: urllib3<3
24
24
  Requires-Dist: numpy>=1.21.0,<3
25
25
  Requires-Dist: Pillow>=9.3.0
26
26
  Requires-Dist: pypng>=0.0.20
@@ -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.8"
10
10
  description = "A python wrapper for Ansys EnSight"
11
11
  readme = "README.rst"
12
12
  requires-python = ">=3.10,<3.14"
@@ -27,10 +27,10 @@ classifiers = [
27
27
 
28
28
  dependencies = [
29
29
  "importlib-metadata>=4.0; python_version<='3.8'",
30
- "ansys-api-pyensight==0.4.8",
30
+ "ansys-api-pyensight==0.4.9",
31
31
  "requests>=2.28.2",
32
32
  "docker>=6.1.0",
33
- "urllib3<2.4.0",
33
+ "urllib3<3",
34
34
  "numpy>=1.21.0,<3",
35
35
  "Pillow>=9.3.0",
36
36
  "pypng>=0.0.20",
@@ -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
@@ -97,7 +97,7 @@ def get_host_port(uri: str) -> Tuple[str, int]:
97
97
  port = (
98
98
  parse_results.port
99
99
  if parse_results.port
100
- else (443 if re.search("^https|wss$", parse_results.scheme) else None)
100
+ else (443 if re.search(r"^https|wss$", parse_results.scheme) else None)
101
101
  )
102
102
  return (parse_results.host, port)
103
103
 
@@ -156,7 +156,9 @@ class DVS(dvs_base):
156
156
  arch = "win64" if self._is_windows() else "linux_2.6_64"
157
157
  apex_libs = os.path.join(apex_path, "machines", arch)
158
158
  python_path = glob.glob(os.path.join(apex_libs, "Python-3.*"))[-1]
159
- apex_py_version = re.search("Python-3.([0-9]+).([0-9]+)", os.path.basename(python_path))
159
+ apex_py_version = re.search(
160
+ r"Python-3.([0-9]+).([0-9]+)", os.path.basename(python_path)
161
+ )
160
162
  apex_py_major_version = apex_py_version.group(1)
161
163
  lib_path = os.path.join(python_path, "lib", f"python3.{apex_py_major_version}")
162
164
  if self._is_windows():
@@ -455,7 +455,7 @@ class EnShellGRPC(object):
455
455
  "Error getting CEI_HOME env var from the Docker container.\n{ret}\n"
456
456
  ) # pragma: no cover
457
457
  self._cei_home = cei_home_line[equal_sign_loc + 1 :]
458
- m = re.search("/v(\d\d\d)/", self._cei_home)
458
+ m = re.search(r"/v(\d\d\d)/", self._cei_home)
459
459
  if not m: # pragma: no cover
460
460
  self.stop_server() # pragma: no cover
461
461
  raise RuntimeError(
@@ -1138,8 +1138,8 @@ class LibUserd(object):
1138
1138
  >>> from ansys.pyensight.core import libuserd
1139
1139
  >>> l = libuserd.LibUserd()
1140
1140
  >>> l.initialize()
1141
- >>> readers = l.query_format(r"D:\data\Axial_001.res")
1142
- >>> data = readers[0].read_dataset(r"D:\data\Axial_001.res")
1141
+ >>> readers = l.query_format("D:\\data\\Axial_001.res")
1142
+ >>> data = readers[0].read_dataset("D:\\data\\Axial_001.res")
1143
1143
  >>> part = data.parts[0]
1144
1144
  >>> print(part, part.nodes())
1145
1145
  >>> l.shutdown()
@@ -1164,7 +1164,7 @@ class Session:
1164
1164
  --------
1165
1165
  >>> from ansys.pyensight.core import LocalLauncher
1166
1166
  >>> session = LocalLauncher().start()
1167
- >>> session.load_data(r'D:\data\CFX\example_data.res')
1167
+ >>> session.load_data('D:\\data\\CFX\\example_data.res')
1168
1168
 
1169
1169
  """
1170
1170
  self._establish_connection()
@@ -1431,7 +1431,7 @@ class Session:
1431
1431
  >>> def cb(v: str):
1432
1432
  >>> print("Event:", v)
1433
1433
  >>> s.add_callback("ensight.objs.core", "partlist", ["PARTS"], cb)
1434
- >>> s.load_data(r"D:\ANSYSDev\data\CFX\HeatingCoil_001.res")
1434
+ >>> s.load_data("D:\\ANSYSDev\\data\\CFX\\HeatingCoil_001.res")
1435
1435
  """
1436
1436
  self._establish_connection()
1437
1437
  # shorten the tag up to the query block. Macros are only legal in the query block.
@@ -396,7 +396,7 @@ class Omniverse:
396
396
  >>> from ansys.pyensight.core import LocalLauncher
397
397
  >>> session = LocalLauncher().start()
398
398
  >>> ov = session.ensight.utils.omniverse
399
- >>> ov.create_connection(r"D:\Omniverse\Example")
399
+ >>> ov.create_connection("D:\\Omniverse\\Example")
400
400
  >>> ov.update()
401
401
  >>> ov.close_connection()
402
402
 
@@ -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,243 @@ 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.function("global")
82
+ self.ensight.view_transf.fit()
83
+ self._initialize_simba_view()
84
+ self.render()
85
+ return self.get_camera()
86
+
87
+ def set_view(self, value: str):
88
+ """Set the view."""
89
+ self.ensight.view_transf.function("global")
90
+ if value != "isometric":
91
+ new_value = value[1].upper() + value[0]
92
+ self.ensight.view_transf.view_recall(new_value)
93
+ else:
94
+ self.views.set_view_direction(
95
+ 1, 1, 1, perspective=self.ensight.objs.core.vports[0].PERSPECTIVE
96
+ )
97
+ self.auto_scale()
98
+ return self.get_camera()
99
+
100
+ def get_camera(self):
101
+ """Get EnSight camera settings in VTK format."""
102
+ vport = self.ensight.objs.core.VPORTS[0]
103
+ position, focal_point, view_up, parallel_scale = self.compute_camera_from_ensight_opengl()
104
+ vport = self.ensight.objs.core.VPORTS[0]
105
+ view_angle = 2 * vport.PERSPECTIVEANGLE
106
+ # The parameter parallel scale is the actual parallel scale only
107
+ # if the vport is in orthographic mode. If not, it is defined as the
108
+ # inverge of the tangent of half of the field of view
109
+ parallel_scale = parallel_scale
110
+ return {
111
+ "orthographic": not vport.PERSPECTIVE,
112
+ "view_up": view_up,
113
+ "position": position,
114
+ "focal_point": focal_point,
115
+ "view_angle": view_angle,
116
+ "parallel_scale": parallel_scale,
117
+ "reset_focal_point": self._original_look_at,
118
+ "reset_position": self._original_look_from,
119
+ "reset_parallel_scale": self._original_parallel_scale,
120
+ "reset_view_up": self._original_view_up,
121
+ "reset_view_angle": self._original_view_angle,
122
+ }
123
+
124
+ @staticmethod
125
+ def normalize(v):
126
+ """Normalize a numpy vector."""
127
+ norm = np.linalg.norm(v)
128
+ return v / norm if norm > 0 else v
129
+
130
+ @staticmethod
131
+ def rotation_matrix_to_quaternion(m):
132
+ """Convert a numpy rotation matrix to a quaternion."""
133
+ trace = np.trace(m)
134
+ if trace > 0:
135
+ s = 0.5 / np.sqrt(trace + 1.0)
136
+ w = 0.25 / s
137
+ x = (m[2, 1] - m[1, 2]) * s
138
+ y = (m[0, 2] - m[2, 0]) * s
139
+ z = (m[1, 0] - m[0, 1]) * s
140
+ else:
141
+ if m[0, 0] > m[1, 1] and m[0, 0] > m[2, 2]:
142
+ s = 2.0 * np.sqrt(1.0 + m[0, 0] - m[1, 1] - m[2, 2])
143
+ w = (m[2, 1] - m[1, 2]) / s
144
+ x = 0.25 * s
145
+ y = (m[0, 1] + m[1, 0]) / s
146
+ z = (m[0, 2] + m[2, 0]) / s
147
+ elif m[1, 1] > m[2, 2]:
148
+ s = 2.0 * np.sqrt(1.0 + m[1, 1] - m[0, 0] - m[2, 2])
149
+ w = (m[0, 2] - m[2, 0]) / s
150
+ x = (m[0, 1] + m[1, 0]) / s
151
+ y = 0.25 * s
152
+ z = (m[1, 2] + m[2, 1]) / s
153
+ else:
154
+ s = 2.0 * np.sqrt(1.0 + m[2, 2] - m[0, 0] - m[1, 1])
155
+ w = (m[1, 0] - m[0, 1]) / s
156
+ x = (m[0, 2] + m[2, 0]) / s
157
+ y = (m[1, 2] + m[2, 1]) / s
158
+ z = 0.25 * s
159
+ return np.array([x, y, z, w])
160
+
161
+ def compute_model_rotation_quaternion(self, camera_position, focal_point, view_up):
162
+ """Compute the quaternion from the input camera."""
163
+ forward = self.normalize(np.array(focal_point) - np.array(camera_position))
164
+ right = self.normalize(np.cross(forward, view_up))
165
+ true_up = np.cross(right, forward)
166
+ camera_rotation = np.vstack([right, true_up, -forward]).T
167
+ model_rotation = camera_rotation.T
168
+ quat = self.rotation_matrix_to_quaternion(model_rotation)
169
+ return quat
170
+
171
+ @staticmethod
172
+ def quaternion_multiply(q1, q2):
173
+ x1, y1, z1, w1 = q1
174
+ x2, y2, z2, w2 = q2
175
+ w = w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2
176
+ x = w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2
177
+ y = w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2
178
+ z = w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2
179
+ return np.array([x, y, z, w])
180
+
181
+ def quaternion_to_euler(self, q):
182
+ q = self.normalize(q)
183
+ x, y, z, w = q
184
+ sinr_cosp = 2 * (w * x + y * z)
185
+ cosr_cosp = 1 - 2 * (x * x + y * y)
186
+ roll = np.arctan2(sinr_cosp, cosr_cosp)
187
+
188
+ sinp = 2 * (w * y - z * x)
189
+ if abs(sinp) >= 1:
190
+ pitch = np.pi / 2 * np.sign(sinp)
191
+ else:
192
+ pitch = np.arcsin(sinp)
193
+ siny_cosp = 2 * (w * z + x * y)
194
+ cosy_cosp = 1 - 2 * (y * y + z * z)
195
+ yaw = np.arctan2(siny_cosp, cosy_cosp)
196
+
197
+ return np.degrees([roll, pitch, yaw])
198
+
199
+ def compute_camera_from_ensight_opengl(self):
200
+ """Simulate a rotating camera using the current quaternion."""
201
+ if isinstance(self.ensight, ModuleType):
202
+ data = self.ensight.objs.core.VPORTS[0].simba_camera()
203
+ else:
204
+ data = self.ensight._session.cmd("ensight.objs.core.VPORTS[0].simba_camera())")
205
+ camera_position = [data[0], data[1], data[2]]
206
+ focal_point = [data[3], data[4], data[5]]
207
+ view_up = [data[6], data[7], data[8]]
208
+ parallel_scale = 1 / data[9]
209
+ return camera_position, focal_point, self.views._normalize_vector(view_up), parallel_scale
210
+
211
+ def set_camera(
212
+ self, orthographic, view_up=None, position=None, focal_point=None, view_angle=None
213
+ ):
214
+ """Set the EnSight camera settings from the VTK input."""
215
+ self.ensight.view_transf.function("global")
216
+ perspective = "OFF" if orthographic else "ON"
217
+ if orthographic:
218
+ self.ensight.view.perspective(perspective)
219
+ vport = self.ensight.objs.core.VPORTS[0]
220
+ if view_angle:
221
+ vport.PERSPECTIVEANGLE = view_angle / 2
222
+
223
+ if view_up and position and focal_point:
224
+ q_current = self.normalize(np.array(vport.ROTATION.copy()))
225
+ q_target = self.normalize(
226
+ self.compute_model_rotation_quaternion(position, focal_point, view_up)
227
+ )
228
+ q_relative = self.quaternion_multiply(
229
+ q_target, np.array([-q_current[0], -q_current[1], -q_current[2], q_current[3]])
230
+ )
231
+ angles = self.quaternion_to_euler(q_relative)
232
+ self.ensight.view_transf.rotate(*angles)
233
+ self.render()
234
+
235
+ def set_perspective(self, value):
236
+ self.ensight.view_transf.function("global")
237
+ vport = self.ensight.objs.core.VPORTS[0]
238
+ self.ensight.view.perspective(value)
239
+ vport.PERSPECTIVE = value == "ON"
240
+ self.ensight.view_transf.zoom(1)
241
+ self.ensight.view_transf.rotate(0, 0, 0)
242
+ self.render()
243
+ return self.get_camera()
244
+
245
+ def screen_to_world(self, mousex, mousey, invert_y=False, set_center=False):
246
+ mousex = int(mousex)
247
+ mousey = int(mousey)
248
+ if isinstance(self.ensight, ModuleType):
249
+ model_point = self.ensight.objs.core.VPORTS[0].screen_to_coords(
250
+ mousex, mousey, invert_y, set_center
251
+ )
252
+ else:
253
+ model_point = self.ensight._session.cmd(
254
+ f"ensight.objs.core.VPORTS[0].screen_to_coords({mousex}, {mousey}, {invert_y}, {set_center})"
255
+ )
256
+ self.render()
257
+ return {"model_point": model_point, "camera": self.get_camera()}
258
+
259
+ def render(self):
260
+ self.ensight.render()
261
+ self.ensight.refresh(1)
262
+
263
+
31
264
  class Views:
32
265
  """Controls the view in the current EnSight ``Session`` instance."""
33
266
 
34
267
  def __init__(self, ensight: Union["ensight_api.ensight", "ensight"]):
35
268
  self.ensight = ensight
36
269
  self._views_dict: Dict[str, Tuple[int, List[float]]] = {}
270
+ self._simba = _Simba(ensight, self)
37
271
 
38
- # Utilities
39
272
  @staticmethod
40
273
  def _normalize_vector(direction: List[float]) -> List[float]:
41
274
  """Return the normalized input (3D) vector.
@@ -295,14 +528,17 @@ class Views:
295
528
  vportindex : int, optional
296
529
  Viewport to set the view direction for. The default is ``0``.
297
530
  """
298
- self.ensight.view.perspective("OFF")
299
- direction = [xdir, ydir, zdir]
300
531
  vport = self.ensight.objs.core.VPORTS[vportindex]
532
+ if not perspective:
533
+ self.ensight.view.perspective("OFF")
534
+ vport.PERSPECTIVE = False
535
+ direction = [xdir, ydir, zdir]
301
536
  rots = vport.ROTATION.copy()
302
537
  rots[0:4] = self._convert_view_direction_to_quaternion(direction, up_axis=up_axis)
303
538
  vport.ROTATION = rots
304
539
  if perspective:
305
540
  self.ensight.view.perspective("ON")
541
+ vport.PERSPECTIVE = True
306
542
  self.save_current_view(name=name, vportindex=vportindex)
307
543
 
308
544
  def save_current_view(