ansys-pyensight-core 0.8.4__py3-none-any.whl → 0.8.6__py3-none-any.whl

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 (26) hide show
  1. ansys/pyensight/core/exts/ansys.geometry.service/ansys/geometry/service/__init__.py +1 -0
  2. ansys/pyensight/core/exts/ansys.geometry.service/ansys/geometry/service/extension.py +407 -0
  3. ansys/pyensight/core/exts/ansys.geometry.service/config/extension.toml +59 -0
  4. ansys/pyensight/core/exts/ansys.geometry.service/data/icon.png +0 -0
  5. ansys/pyensight/core/exts/ansys.geometry.service/data/preview.png +0 -0
  6. ansys/pyensight/core/exts/ansys.geometry.service/docs/CHANGELOG.md +8 -0
  7. ansys/pyensight/core/exts/ansys.geometry.service/docs/README.md +13 -0
  8. ansys/pyensight/core/exts/ansys.geometry.service/docs/index.rst +18 -0
  9. ansys/pyensight/core/exts/ansys.geometry.serviceui/ansys/geometry/serviceui/__init__.py +1 -0
  10. ansys/pyensight/core/exts/ansys.geometry.serviceui/ansys/geometry/serviceui/extension.py +193 -0
  11. ansys/pyensight/core/exts/ansys.geometry.serviceui/config/extension.toml +49 -0
  12. ansys/pyensight/core/exts/ansys.geometry.serviceui/data/icon.png +0 -0
  13. ansys/pyensight/core/exts/ansys.geometry.serviceui/data/preview.png +0 -0
  14. ansys/pyensight/core/exts/ansys.geometry.serviceui/docs/CHANGELOG.md +8 -0
  15. ansys/pyensight/core/exts/ansys.geometry.serviceui/docs/README.md +13 -0
  16. ansys/pyensight/core/exts/ansys.geometry.serviceui/docs/index.rst +18 -0
  17. ansys/pyensight/core/launcher.py +36 -1
  18. ansys/pyensight/core/locallauncher.py +3 -1
  19. ansys/pyensight/core/utils/dsg_server.py +36 -11
  20. ansys/pyensight/core/utils/omniverse.py +151 -95
  21. ansys/pyensight/core/utils/omniverse_dsg_server.py +91 -37
  22. {ansys_pyensight_core-0.8.4.dist-info → ansys_pyensight_core-0.8.6.dist-info}/METADATA +1 -1
  23. ansys_pyensight_core-0.8.6.dist-info/RECORD +52 -0
  24. ansys_pyensight_core-0.8.4.dist-info/RECORD +0 -36
  25. {ansys_pyensight_core-0.8.4.dist-info → ansys_pyensight_core-0.8.6.dist-info}/LICENSE +0 -0
  26. {ansys_pyensight_core-0.8.4.dist-info → ansys_pyensight_core-0.8.6.dist-info}/WHEEL +0 -0
@@ -1,8 +1,9 @@
1
+ import glob
1
2
  import os
2
3
  import subprocess
3
4
  import sys
4
5
  from types import ModuleType
5
- from typing import TYPE_CHECKING, List, Optional, Union
6
+ from typing import TYPE_CHECKING, Optional, Union
6
7
 
7
8
  import psutil
8
9
 
@@ -12,6 +13,8 @@ if TYPE_CHECKING:
12
13
  except ImportError:
13
14
  from ansys.api.pyensight import ensight_api
14
15
 
16
+ import ansys.pyensight.core
17
+
15
18
 
16
19
  class Omniverse:
17
20
  """Provides the ``ensight.utils.omniverse`` interface.
@@ -21,7 +24,7 @@ class Omniverse:
21
24
 
22
25
  Parameters
23
26
  ----------
24
- interface:
27
+ interface: Union["ensight_api.ensight", "ensight"]
25
28
  Entity that provides the ``ensight`` namespace. In the case of
26
29
  EnSight Python, the ``ensight`` module is passed. In the case
27
30
  of PyEnSight, ``Session.ensight`` is passed.
@@ -35,20 +38,93 @@ class Omniverse:
35
38
 
36
39
  Examples
37
40
  --------
38
- ::
39
- from ansys.pyensight.core import LocalLauncher
40
- session = LocalLauncher().start()
41
- ov = session.ensight.utils.omniverse
42
- ov.create_connection()
43
- ov.update()
44
- ov.close_connection()
41
+
42
+ >>> from ansys.pyensight.core import LocalLauncher
43
+ >>> session = LocalLauncher().start()
44
+ >>> ov = session.ensight.utils.omniverse
45
+ >>> ov.create_connection()
46
+ >>> ov.update()
47
+ >>> ov.close_connection()
45
48
 
46
49
  """
47
50
 
48
51
  def __init__(self, interface: Union["ensight_api.ensight", "ensight"]):
49
52
  self._ensight = interface
50
53
  self._server_pid: Optional[int] = None
51
- self._interpreter: List[str] = []
54
+ self._interpreter: str = ""
55
+
56
+ @staticmethod
57
+ def find_kit_filename(fallback_directory: Optional[str] = None) -> Optional[str]:
58
+ """
59
+ Use a combination of the current omniverse application and the information
60
+ in the local .nvidia-omniverse/config/omniverse.toml file to come up with
61
+ the pathname of a kit executable suitable for hosting another copy of the
62
+ ansys.geometry.server kit.
63
+
64
+ Returns
65
+ -------
66
+ Optional[str]
67
+ The pathname of a kit executable or None
68
+
69
+ """
70
+ # parse the toml config file for the location of the installed apps
71
+ try:
72
+ import tomllib
73
+ except ModuleNotFoundError:
74
+ import pip._vendor.tomli as tomllib
75
+
76
+ homedir = os.path.expanduser("~")
77
+ ov_config = os.path.join(homedir, ".nvidia-omniverse", "config", "omniverse.toml")
78
+ if not os.path.exists(ov_config):
79
+ return None
80
+ # read the Omniverse configuration toml file
81
+ with open(ov_config, "r") as ov_file:
82
+ ov_data = ov_file.read()
83
+ config = tomllib.loads(ov_data)
84
+ appdir = config.get("paths", {}).get("library_root", fallback_directory)
85
+
86
+ # If we are running inside an Omniverse app, use that information
87
+ try:
88
+ import omni.kit.app
89
+
90
+ # get the current application
91
+ app = omni.kit.app.get_app()
92
+ app_name = app.get_app_filename().split(".")[-1]
93
+ app_version = app.get_app_version().split("-")[0]
94
+ # and where it is installed
95
+ appdir = os.path.join(appdir, f"{app_name}-{app_version}")
96
+ except ModuleNotFoundError:
97
+ # Names should be like: "C:\\Users\\foo\\AppData\\Local\\ov\\pkg\\create-2023.2.3\\launcher.toml"
98
+ target = None
99
+ target_version = None
100
+ for d in glob.glob(os.path.join(appdir, "*", "launcher.toml")):
101
+ test_dir = os.path.dirname(d)
102
+ # the name will be something like "create-2023.2.3"
103
+ name = os.path.basename(test_dir).split("-")
104
+ if len(name) != 2:
105
+ continue
106
+ if name[0] not in ("kit", "create", "view"):
107
+ continue
108
+ if (target_version is None) or (name[1] > target_version):
109
+ target = test_dir
110
+ target_version = name[1]
111
+ if target is None:
112
+ return None
113
+ appdir = target
114
+
115
+ # Windows: 'kit.bat' in '.' or 'kit' followed by 'kit.exe' in '.' or 'kit'
116
+ # Linux: 'kit.sh' in '.' or 'kit' followed by 'kit' in '.' or 'kit'
117
+ exe_names = ["kit.sh", "kit"]
118
+ if sys.platform.startswith("win"):
119
+ exe_names = ["kit.bat", "kit.exe"]
120
+
121
+ # look in 4 places...
122
+ for dir_name in [appdir, os.path.join(appdir, "kit")]:
123
+ for exe_name in exe_names:
124
+ if os.path.exists(os.path.join(dir_name, exe_name)):
125
+ return os.path.join(dir_name, exe_name)
126
+
127
+ return None
52
128
 
53
129
  def _check_modules(self) -> None:
54
130
  """Verify that the Python interpreter is correct
@@ -60,53 +136,26 @@ class Omniverse:
60
136
 
61
137
  Raises
62
138
  ------
63
- RuntimeError if the necessary modules are missing.
139
+ RuntimeError
140
+ if the necessary modules are missing.
64
141
 
65
142
  """
66
143
  # One time check for this
67
144
  if len(self._interpreter):
68
145
  return
69
- try:
70
- # Note: the EnSight embedded interpreter will not have these
71
- import omni.client # noqa: F401
72
- except ImportError:
73
- raise RuntimeError("The module requires the omni module to be installed.") from None
74
146
 
75
- try:
76
- # if we can import pxr, then we can just use sys.executable
77
- from pxr import Gf, Sdf, Usd, UsdGeom, UsdLux, UsdShade # noqa: F401
78
-
79
- if os.path.basename(sys.executable).startswith("kit"):
80
- # we are running inside of an Omniverse app like Create, use the 'kit' script
81
- raise ImportError("Internal retry")
82
-
83
- self._interpreter = [sys.executable]
147
+ kit_exe = self.find_kit_filename()
148
+ if kit_exe:
149
+ self._interpreter = kit_exe
84
150
  return
85
- except ImportError:
86
- # Can we find 'kit.bat' or 'kit.sh' (we may be running in it)?
87
- # Interesting cases: something/kit/python/python.exe,
88
- # something/kit/kit.exe. All mapped to something/kit.{bat,sh} if found.
89
- ov_dir = os.path.dirname(sys.executable)
90
- for _ in range(3):
91
- for name in ("kit.bat", "kit.sh"):
92
- exe_name = os.path.join(ov_dir, name)
93
- if os.path.exists(exe_name):
94
- self._interpreter = [
95
- exe_name,
96
- "--enable",
97
- "omni.client",
98
- "--enable",
99
- "omni.usd",
100
- "--exec",
101
- ]
102
- return
103
- ov_dir = os.path.dirname(ov_dir)
104
- raise RuntimeError("Unable to detect a copy of the Omniverse kit executable.") from None
105
-
106
- def _is_running_omniverse(self) -> bool:
151
+ raise RuntimeError("Unable to detect a copy of the Omniverse kit executable.") from None
152
+
153
+ def is_running_omniverse(self) -> bool:
107
154
  """Check that an Omniverse connection is active
155
+
108
156
  Returns
109
157
  -------
158
+ bool
110
159
  True if the connection is active, False otherwise.
111
160
  """
112
161
  if self._server_pid is None:
@@ -121,8 +170,10 @@ class Omniverse:
121
170
  omniverse_path: str,
122
171
  include_camera: bool = False,
123
172
  normalize_geometry: bool = False,
173
+ temporal: bool = False,
124
174
  live: bool = True,
125
175
  debug_filename: str = "",
176
+ options: dict = {},
126
177
  ) -> None:
127
178
  """Ensure that an EnSight dsg -> omniverse server is running
128
179
 
@@ -143,6 +194,8 @@ class Omniverse:
143
194
  Omniverse units are in meters. If the source dataset is not in the correct
144
195
  unit system or is just too large/small, this option will remap the geometry
145
196
  to a unit cube. Defaults to False.
197
+ temporal : bool
198
+ If True, save all timesteps.
146
199
  live : bool
147
200
  If True, one can call 'update()' to send updated geometry to Omniverse.
148
201
  If False, the Omniverse connection will push a single update and then
@@ -150,53 +203,46 @@ class Omniverse:
150
203
  debug_filename : str
151
204
  If the name of a file is provided, it will be used to save logging information on
152
205
  the connection between EnSight and Omniverse.
153
-
206
+ options : dict
207
+ Allows for a fallback for the grpc host/port and the security token.
154
208
  """
155
209
  if not isinstance(self._ensight, ModuleType):
156
210
  self._ensight._session.ensight_version_check("2023 R2")
157
211
  self._check_modules()
158
- if self._is_running_omniverse():
212
+ if self.is_running_omniverse():
159
213
  raise RuntimeError("An Omniverse server connection is already active.")
160
- # Make sure the internal ui module is loaded
161
- self._ensight._session.cmd("import enspyqtgui_int", do_eval=False)
162
- # Get the gRPC connection details and use them to launch the service
163
- port = self._ensight._session.grpc.port()
164
- hostname = self._ensight._session.grpc.host
165
- token = self._ensight._session.grpc.security_token
166
- script_name = "omniverse_dsg_server.py"
167
- working_dir = os.path.dirname(__file__)
168
- cmd = [
169
- script_name,
170
- "--host",
171
- hostname,
172
- "--port",
173
- str(port),
174
- "--path",
175
- omniverse_path,
176
- ]
177
- if live:
178
- cmd.extend(["--live"])
179
- if include_camera:
180
- cmd.extend(["--vrmode"])
214
+ if not isinstance(self._ensight, ModuleType):
215
+ # Make sure the internal ui module is loaded
216
+ self._ensight._session.cmd("import enspyqtgui_int", do_eval=False)
217
+ # Get the gRPC connection details and use them to launch the service
218
+ port = self._ensight._session.grpc.port()
219
+ hostname = self._ensight._session.grpc.host
220
+ token = self._ensight._session.grpc.security_token
221
+ else:
222
+ hostname = options.get("host", "127.0.0.1")
223
+ port = options.get("port", 12345)
224
+ token = options.get("security", "")
225
+
226
+ # Launch the server via the 'ansys.geometry.service' kit
227
+ dsg_uri = f"grpc://{hostname}:{port}"
228
+ kit_dir = os.path.join(os.path.dirname(ansys.pyensight.core.__file__), "exts")
229
+ cmd = [self._interpreter]
230
+ cmd.extend(["--ext-folder", kit_dir])
231
+ cmd.extend(["--enable", "ansys.geometry.service"])
181
232
  if token:
182
- cmd.extend(["--security", token])
183
- # if temporal:
184
- # cmd.extend(["--animation"])
185
- # else:
186
- # cmd.extend(["--no-animation"])
187
- if debug_filename:
188
- cmd.extend(["--log_file", debug_filename])
189
- cmd.extend(["--verbose", "1"])
233
+ cmd.append(f"--/exts/ansys.geometry.service/securityCode={token}")
234
+ if temporal:
235
+ cmd.append("--/exts/ansys.geometry.service/temporal=1")
236
+ if not include_camera:
237
+ cmd.append("--/exts/ansys.geometry.service/vrmode=1")
190
238
  if normalize_geometry:
191
- cmd.extend(["--normalize_geometry"])
192
- # if using kit.bat, convert args into a string, otherwise, just use them
193
- cmdline = []
194
- cmdline.extend(self._interpreter)
195
- if len(self._interpreter) > 1:
196
- cmd = [" ".join(cmd)]
197
- cmdline.extend(cmd)
239
+ cmd.append("--/exts/ansys.geometry.service/normalizeGeometry=1")
240
+ cmd.append(f"--/exts/ansys.geometry.service/omniUrl={omniverse_path}")
241
+ cmd.append(f"--/exts/ansys.geometry.service/dsgUrl={dsg_uri}")
242
+ cmd.append("--/exts/ansys.geometry.service/run=1")
198
243
  env_vars = os.environ.copy()
199
- process = subprocess.Popen(cmdline, close_fds=True, env=env_vars, cwd=working_dir)
244
+ working_dir = os.path.join(os.path.dirname(ansys.pyensight.core.__file__), "utils")
245
+ process = subprocess.Popen(cmd, close_fds=True, env=env_vars, cwd=working_dir)
200
246
  self._server_pid = process.pid
201
247
 
202
248
  def close_connection(self) -> None:
@@ -206,7 +252,7 @@ class Omniverse:
206
252
 
207
253
  """
208
254
  self._check_modules()
209
- if not self._is_running_omniverse():
255
+ if not self.is_running_omniverse():
210
256
  return
211
257
  proc = psutil.Process(self._server_pid)
212
258
  for child in proc.children(recursive=True):
@@ -223,17 +269,27 @@ class Omniverse:
223
269
  pass
224
270
  self._server_pid = None
225
271
 
226
- def update(self) -> None:
272
+ def update(self, temporal: bool = False) -> None:
227
273
  """Update the geometry in Omniverse
228
274
 
229
- Push the current EnSight scene to the current Omniverse connection.
275
+ Export the current EnSight scene to the current Omniverse connection.
230
276
 
277
+ Parameters
278
+ ----------
279
+ temporal : bool
280
+ If True, export all timesteps.
231
281
  """
232
- if not isinstance(self._ensight, ModuleType):
233
- self._ensight._session.ensight_version_check("2023 R2")
282
+ update_cmd = "dynamicscenegraph://localhost/client/update"
283
+ if temporal:
284
+ update_cmd += "?timesteps=1"
234
285
  self._check_modules()
235
- if not self._is_running_omniverse():
286
+ if not self.is_running_omniverse():
236
287
  raise RuntimeError("No Omniverse server connection is currently active.")
237
- update_cmd = "dynamicscenegraph://localhost/client/update"
238
- cmd = f'enspyqtgui_int.dynamic_scene_graph_command("{update_cmd}")'
239
- self._ensight._session.cmd(cmd, do_eval=False)
288
+ if not isinstance(self._ensight, ModuleType):
289
+ self._ensight._session.ensight_version_check("2023 R2")
290
+ cmd = f'enspyqtgui_int.dynamic_scene_graph_command("{update_cmd}")'
291
+ self._ensight._session.cmd(cmd, do_eval=False)
292
+ else:
293
+ import enspyqtgui_int
294
+
295
+ enspyqtgui_int.dynamic_scene_graph_command(f"{update_cmd}")
@@ -232,18 +232,31 @@ class OmniverseWrapper:
232
232
  -------
233
233
  A unique USD name.
234
234
  """
235
+ orig_name = name
235
236
  # return any previously generated name
236
237
  if (name, id_name) in self._cleaned_names:
237
238
  return self._cleaned_names[(name, id_name)]
238
239
  # replace invalid characters. EnSight uses a number of characters that are illegal in USD names.
239
- name = name.replace("+", "_").replace("-", "_")
240
- name = name.replace(".", "_").replace(":", "_")
241
- name = name.replace("[", "_").replace("]", "_")
242
- name = name.replace("(", "_").replace(")", "_")
243
- name = name.replace("<", "_").replace(">", "_")
244
- name = name.replace("/", "_").replace("=", "_")
245
- name = name.replace(",", "_").replace(" ", "_")
246
- name = name.replace("\\", "_")
240
+ replacements = {
241
+ ord("+"): "_",
242
+ ord("-"): "_",
243
+ ord("."): "_",
244
+ ord(":"): "_",
245
+ ord("["): "_",
246
+ ord("]"): "_",
247
+ ord("("): "_",
248
+ ord(")"): "_",
249
+ ord("<"): "_",
250
+ ord(">"): "_",
251
+ ord("/"): "_",
252
+ ord("="): "_",
253
+ ord(","): "_",
254
+ ord(" "): "_",
255
+ ord("\\"): "_",
256
+ }
257
+ name = name.translate(replacements)
258
+ if name[0].isdigit():
259
+ name = f"_{name}"
247
260
  if id_name is not None:
248
261
  name = name + "_" + str(id_name)
249
262
  if name in self._cleaned_names.values():
@@ -252,7 +265,7 @@ class OmniverseWrapper:
252
265
  self._cleaned_index += 1
253
266
  name = f"{name}_{self._cleaned_index}"
254
267
  # store off the cleaned name
255
- self._cleaned_names[(name, id_name)] = name
268
+ self._cleaned_names[(orig_name, id_name)] = name
256
269
  return name
257
270
 
258
271
  @staticmethod
@@ -300,10 +313,12 @@ class OmniverseWrapper:
300
313
  matrix=[1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0],
301
314
  diffuse=[1.0, 1.0, 1.0, 1.0],
302
315
  variable=None,
316
+ timeline=[0.0, 0.0],
317
+ first_timestep=False,
303
318
  ):
304
319
  # 1D texture map for variables https://graphics.pixar.com/usd/release/tut_simple_shading.html
305
320
  # create the part usd object
306
- partname = self.clean_name(name, id)
321
+ partname = self.clean_name(name + str(id) + str(timeline[0]))
307
322
  stage_name = "/Parts/" + partname + ".usd"
308
323
  part_stage_url = self.stage_url(stage_name)
309
324
  omni.client.delete(part_stage_url)
@@ -342,13 +357,29 @@ class OmniverseWrapper:
342
357
  self.create_dsg_material(
343
358
  part_stage, mesh, "/" + partname, diffuse=diffuse, variable=variable
344
359
  )
345
- part_stage.GetRootLayer().Save()
360
+
361
+ # add a layer in the group hierarchy for the timestep
362
+ timestep_group_path = parent_prim.GetPath().AppendChild(
363
+ self.clean_name("t" + str(timeline[0]), None)
364
+ )
365
+ timestep_prim = UsdGeom.Xform.Define(self._stage, timestep_group_path)
366
+ visibility_attr = UsdGeom.Imageable(timestep_prim).GetVisibilityAttr()
367
+ if first_timestep:
368
+ visibility_attr.Set("inherited", Usd.TimeCode.EarliestTime())
369
+ else:
370
+ visibility_attr.Set("invisible", Usd.TimeCode.EarliestTime())
371
+ visibility_attr.Set("inherited", timeline[0])
372
+ # Final timestep has timeline[0]==timeline[1]. Leave final timestep visible.
373
+ if timeline[0] < timeline[1]:
374
+ visibility_attr.Set("invisible", timeline[1])
346
375
 
347
376
  # glue it into our stage
348
- path = parent_prim.GetPath().AppendChild("part_ref_" + partname)
377
+ path = timestep_prim.GetPath().AppendChild("part_ref_" + partname)
349
378
  part_ref = self._stage.OverridePrim(path)
350
379
  part_ref.GetReferences().AddReference("." + stage_name)
351
380
 
381
+ part_stage.GetRootLayer().Save()
382
+
352
383
  return part_stage_url
353
384
 
354
385
  def create_dsg_material(
@@ -413,13 +444,15 @@ class OmniverseWrapper:
413
444
  omni.client.delete(uriPath)
414
445
  omni.client.copy("scratch/Textures", uriPath)
415
446
 
416
- def create_dsg_root(self, camera=None):
447
+ def create_dsg_root(self):
417
448
  root_name = "/Root"
418
449
  root_prim = UsdGeom.Xform.Define(self._stage, root_name)
419
450
  # Define the defaultPrim as the /Root prim
420
451
  root_prim = self._stage.GetPrimAtPath(root_name)
421
452
  self._stage.SetDefaultPrim(root_prim)
453
+ return root_prim
422
454
 
455
+ def update_camera(self, camera):
423
456
  if camera is not None:
424
457
  cam_name = "/Root/Cam"
425
458
  cam_prim = UsdGeom.Xform.Define(self._stage, cam_name)
@@ -454,7 +487,6 @@ class OmniverseWrapper:
454
487
 
455
488
  # set the updated camera
456
489
  geom_cam.SetFromCamera(cam)
457
- return root_prim
458
490
 
459
491
  def create_dsg_group(
460
492
  self,
@@ -481,19 +513,22 @@ class OmniverseWrapper:
481
513
  ],
482
514
  ):
483
515
  path = parent_prim.GetPath().AppendChild(self.clean_name(name))
484
- group_prim = UsdGeom.Xform.Define(self._stage, path)
485
- # At present, the group transforms have been cooked into the vertices so this is not needed
486
- matrixOp = group_prim.AddXformOp(
487
- UsdGeom.XformOp.TypeTransform, UsdGeom.XformOp.PrecisionDouble
488
- )
489
- matrixOp.Set(Gf.Matrix4d(*matrix).GetTranspose())
490
- self.log(f"Created group:'{name}' {str(obj_type)}")
516
+ group_prim = UsdGeom.Xform.Get(self._stage, path)
517
+ if not group_prim:
518
+ group_prim = UsdGeom.Xform.Define(self._stage, path)
519
+ # At present, the group transforms have been cooked into the vertices so this is not needed
520
+ matrixOp = group_prim.AddXformOp(
521
+ UsdGeom.XformOp.TypeTransform, UsdGeom.XformOp.PrecisionDouble
522
+ )
523
+ matrixOp.Set(Gf.Matrix4d(*matrix).GetTranspose())
524
+ self.log(f"Created group:'{name}' {str(obj_type)}")
491
525
  return group_prim
492
526
 
493
527
  def uploadMaterial(self):
494
528
  uriPath = self._destinationPath + "/Materials"
495
529
  omni.client.delete(uriPath)
496
- omni.client.copy("resources/Materials", uriPath)
530
+ fullpath = os.path.join(os.path.dirname(__file__), "resources", "Materials")
531
+ omni.client.copy(fullpath, uriPath)
497
532
 
498
533
  def createMaterial(self, mesh):
499
534
  # Create a material instance for this in USD
@@ -609,6 +644,8 @@ class OmniverseUpdateHandler(UpdateHandler):
609
644
  super().__init__()
610
645
  self._omni = omni
611
646
  self._group_prims: Dict[int, Any] = dict()
647
+ self._root_prim = None
648
+ self._sent_textures = False
612
649
 
613
650
  def add_group(self, id: int, view: bool = False) -> None:
614
651
  super().add_group(id, view)
@@ -624,30 +661,35 @@ class OmniverseUpdateHandler(UpdateHandler):
624
661
  else:
625
662
  # Map a view command into a new Omniverse stage and populate it with materials/lights.
626
663
  # Create a new root stage in Omniverse
627
- self._omni.create_new_stage()
628
- # Create the root group/camera
629
- camera_info = group
630
- if self.session.vrmode:
631
- camera_info = None
632
- prim = self._omni.create_dsg_root(camera=camera_info)
633
- # Create a distance and dome light in the scene
634
- self._omni.createDomeLight("./Materials/000_sky.exr")
635
- # Upload a material and textures to the Omniverse server
636
- self._omni.uploadMaterial()
637
- self._omni.create_dsg_variable_textures(self.session.variables)
638
- # record
639
- self._group_prims[id] = prim
664
+
665
+ # Create or update the root group/camera
666
+ if not self.session.vrmode:
667
+ self._omni.update_camera(camera=group)
668
+
669
+ # record
670
+ self._group_prims[id] = self._root_prim
671
+
672
+ if self._omni._stage is not None:
673
+ self._omni._stage.SetStartTimeCode(self.session.time_limits[0])
674
+ self._omni._stage.SetEndTimeCode(self.session.time_limits[1])
675
+ self._omni._stage.SetTimeCodesPerSecond(1)
676
+ self._omni._stage.SetFramesPerSecond(1)
677
+
678
+ # Send the variable textures. Safe to do so once the first view is processed.
679
+ if not self._sent_textures:
680
+ self._omni.create_dsg_variable_textures(self.session.variables)
681
+ self._sent_textures = True
640
682
 
641
683
  def add_variable(self, id: int) -> None:
642
684
  super().add_variable(id)
643
685
 
644
686
  def finalize_part(self, part: Part) -> None:
645
687
  # generate an Omniverse compliant mesh from the Part
646
- command, verts, conn, normals, tcoords, var_cmd = part.build()
688
+ command, verts, conn, normals, tcoords, var_cmd = part.nodal_surface_rep()
647
689
  if command is None:
648
690
  return
649
691
  parent_prim = self._group_prims[command.parent_id]
650
- obj_id = self._session.mesh_block_count
692
+ obj_id = self.session.mesh_block_count
651
693
  matrix = command.matrix4x4
652
694
  name = command.name
653
695
  color = [
@@ -668,6 +710,8 @@ class OmniverseUpdateHandler(UpdateHandler):
668
710
  matrix=matrix,
669
711
  diffuse=color,
670
712
  variable=var_cmd,
713
+ timeline=self.session.cur_timeline,
714
+ first_timestep=(self.session.cur_timeline[0] == self.session.time_limits[0]),
671
715
  )
672
716
  super().finalize_part(part)
673
717
 
@@ -684,6 +728,14 @@ class OmniverseUpdateHandler(UpdateHandler):
684
728
  # clear the group Omni prims list
685
729
  self._group_prims = dict()
686
730
 
731
+ self._omni.create_new_stage()
732
+ self._root_prim = self._omni.create_dsg_root()
733
+ # Create a distance and dome light in the scene
734
+ self._omni.createDomeLight("./Materials/000_sky.exr")
735
+ # Upload a material to the Omniverse server
736
+ self._omni.uploadMaterial()
737
+ self._sent_textures = False
738
+
687
739
  def end_update(self) -> None:
688
740
  super().end_update()
689
741
  # Stage update complete
@@ -810,6 +862,8 @@ if __name__ == "__main__":
810
862
 
811
863
  # Simple pull request
812
864
  dsg_link.request_an_update(animation=args.animation)
865
+ # Handle the update block
866
+ dsg_link.handle_one_update()
813
867
 
814
868
  # Live operation
815
869
  if args.live:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ansys-pyensight-core
3
- Version: 0.8.4
3
+ Version: 0.8.6
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>
@@ -0,0 +1,52 @@
1
+ ansys/pyensight/core/__init__.py,sha256=6iKVEEtxt-6mw7wu_AocOGYO1T1WYHAnk-X_jeTeA8k,828
2
+ ansys/pyensight/core/deep_pixel_view.html,sha256=oZmcCIS3Dqqsoj8oheYubLAH2ZVKXao3iJM2WXYBEKs,3421
3
+ ansys/pyensight/core/dockerlauncher.py,sha256=8ZqwIMtXvb2knax1SvhysstZuMRpc_9MXdatXF1UCHA,28203
4
+ ansys/pyensight/core/enscontext.py,sha256=GSKkjZt1QEPyHEQ59EEBgKGMik9vjCdR9coR4uX7fEw,12141
5
+ ansys/pyensight/core/enshell_grpc.py,sha256=ijRcByqdG0ZIi958Co860w2mnBIklfguI6s8sewcR8Q,15904
6
+ ansys/pyensight/core/ensight_grpc.py,sha256=BJaErleSPrtI8myTIh0m9awFWPaUxrQmHpbuyR3RpM4,16847
7
+ ansys/pyensight/core/ensobj.py,sha256=uDtM2KHcAwd4hu5pcUYWbSD729ApHGIvuqZhEq8PxTI,18558
8
+ ansys/pyensight/core/launch_ensight.py,sha256=UyTDDmxru864YAihTY9EQ5NIbKFRiLpWGPHMu7JUgyY,6175
9
+ ansys/pyensight/core/launcher.py,sha256=izjzeLapNIVP8vsA1-mET7qP6yjzI-M1q85w7C5fHSc,12280
10
+ ansys/pyensight/core/listobj.py,sha256=Trw87IxIMXtmUd1DzywRmMzORU704AG4scX4fqYmO6M,9340
11
+ ansys/pyensight/core/locallauncher.py,sha256=1yrWTba98BdiEz7q6-N4_wlR6s10s9Xs2eQur5tNeyc,14134
12
+ ansys/pyensight/core/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ ansys/pyensight/core/renderable.py,sha256=hm4sXV-ZcpdfC_AJexycAX8zdsbWnsd-tMeUvewGekE,35003
14
+ ansys/pyensight/core/session.py,sha256=AHTRbX0sDlvtUf8lyRoXetiICmLWO7n26Ni9lMy7tBY,74363
15
+ ansys/pyensight/core/sgeo_poll.html,sha256=1M4BIc5CZpYA3b40qzk22NcPCLhjFnWdoS2PrS6Rhn4,752
16
+ ansys/pyensight/core/exts/ansys.geometry.service/ansys/geometry/service/__init__.py,sha256=jWNP3Ue7YZpXD9xopEkwbDillK_lkrMkoPLjDRmcSWQ,26
17
+ ansys/pyensight/core/exts/ansys.geometry.service/ansys/geometry/service/extension.py,sha256=1LhDW_87pXKS1TYYN-PWWwOThUcKsmflLYZcQp9a9jQ,14746
18
+ ansys/pyensight/core/exts/ansys.geometry.service/config/extension.toml,sha256=IJU_ADJfPGzFR-Drk53EprWxLBttk1kMynOzTGl3GA0,2259
19
+ ansys/pyensight/core/exts/ansys.geometry.service/data/icon.png,sha256=FCgr8efQzzkskh9a5W54VX8HXqyAMDkto0c0twoRZjg,24160
20
+ ansys/pyensight/core/exts/ansys.geometry.service/data/preview.png,sha256=7Ac7dYZWWbjrZNohJs1AC0F5FKZFFK9tt_xzFuLCKhY,842766
21
+ ansys/pyensight/core/exts/ansys.geometry.service/docs/CHANGELOG.md,sha256=EnL6fvHVrfCetzBnEe3LnmyHYB9tFCx-wzwCLh6VrJg,184
22
+ ansys/pyensight/core/exts/ansys.geometry.service/docs/README.md,sha256=nBZQ7em3Tk9td5atzsfhl3X9LX4UUH3S7Iawb68HAqU,558
23
+ ansys/pyensight/core/exts/ansys.geometry.service/docs/index.rst,sha256=Zib6dVTosDVOagTBGVxXmQX4GKJVc0l2GYJxK6wm92s,322
24
+ ansys/pyensight/core/exts/ansys.geometry.serviceui/ansys/geometry/serviceui/__init__.py,sha256=jWNP3Ue7YZpXD9xopEkwbDillK_lkrMkoPLjDRmcSWQ,26
25
+ ansys/pyensight/core/exts/ansys.geometry.serviceui/ansys/geometry/serviceui/extension.py,sha256=Gh0fHbJNGBT4829IZnYI8saGxEadwVOiXs3rw5o4ITo,7851
26
+ ansys/pyensight/core/exts/ansys.geometry.serviceui/config/extension.toml,sha256=CjRB1wCaQBX-MagLbeRNIWLKcbn6saLuuCm1FcSBLZI,1788
27
+ ansys/pyensight/core/exts/ansys.geometry.serviceui/data/icon.png,sha256=FCgr8efQzzkskh9a5W54VX8HXqyAMDkto0c0twoRZjg,24160
28
+ ansys/pyensight/core/exts/ansys.geometry.serviceui/data/preview.png,sha256=wC82tRKXp-DHEdg2weOKvmyGjddlRScGWCOHAnzzkm0,824063
29
+ ansys/pyensight/core/exts/ansys.geometry.serviceui/docs/CHANGELOG.md,sha256=2-em3VGioHMdiFBMQuRSJ71HS5NrHhbBVID6q9k3Sls,181
30
+ ansys/pyensight/core/exts/ansys.geometry.serviceui/docs/README.md,sha256=dWqtrZ-qs0bSSanULQ1m44W1FdUcfF5hKIK4sKYoW1c,552
31
+ ansys/pyensight/core/exts/ansys.geometry.serviceui/docs/index.rst,sha256=Q18IW65rMYg1rCufMQYqpMPbeSnY0alKHgvN1ENr5Sc,328
32
+ ansys/pyensight/core/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
+ ansys/pyensight/core/utils/adr.py,sha256=XslZhlwcrSGzOlnhzprOv3ju_ppxxsWBjCnQL5KiNms,3570
34
+ ansys/pyensight/core/utils/dsg_server.py,sha256=fSsxUI1Q44pAyNusBkUTueh4G1xUbIltduLChTVgGRA,30153
35
+ ansys/pyensight/core/utils/export.py,sha256=ZNpU3earAnRMBHZa6I8nTwMYY54WctXApJfMTkREBNA,23189
36
+ ansys/pyensight/core/utils/omniverse.py,sha256=p7uq3VoypQAkQ2fm2cQfHYFhOQGuWONgYilprr7Uf5Y,11943
37
+ ansys/pyensight/core/utils/omniverse_dsg_server.py,sha256=O-eyHMhs6ykevC7ZH82D5as5NU1N-Ve6syz72-hYVi0,34696
38
+ ansys/pyensight/core/utils/parts.py,sha256=zST00r76kjsLLclBaKoOtuYhDUSdQr0vAooOG7AUea0,53372
39
+ ansys/pyensight/core/utils/query.py,sha256=OXKDbf1sOTX0sUvtKcp64LhVl-BcrEsE43w8uMxLOYI,19828
40
+ ansys/pyensight/core/utils/readers.py,sha256=WUpmCtMo9BHlUOwGtIrD5jjyS9HE9wDak8eEjrYeR2Y,11764
41
+ ansys/pyensight/core/utils/support.py,sha256=QI3z9ex7zJxjFbkCPba9DWqWgPFIThORqr0nvRfVjuc,4089
42
+ ansys/pyensight/core/utils/variables.py,sha256=T96aL-qR2FtxH6QafeD9ddcWL9BB6IRSOYs2JauRTlg,95133
43
+ ansys/pyensight/core/utils/views.py,sha256=ZKhJ6vMT7Rdd4bwJ0egMYTV7-D7Q7I19fF2_j_CMQ0o,12489
44
+ ansys/pyensight/core/utils/resources/Materials/000_sky.exr,sha256=xAR1gFd2uxPZDnvgfegdhEhRaqKtZldQDiR_-1rHKO0,8819933
45
+ ansys/pyensight/core/utils/resources/Materials/Fieldstone.mdl,sha256=_7z4BzzrRGUH_x3urV4sc7t7WJBjJn4jWLOw1AQObgY,2035
46
+ ansys/pyensight/core/utils/resources/Materials/Fieldstone/Fieldstone_BaseColor.png,sha256=CyxY5YrvbJxFzUUI-8Q90zOd6xwd85JPzjnUB-vPJ0s,501090
47
+ ansys/pyensight/core/utils/resources/Materials/Fieldstone/Fieldstone_N.png,sha256=Az1m4bK-PWecsErsuZh4-kkUnui9w4TrCxrGwwI091I,795424
48
+ ansys/pyensight/core/utils/resources/Materials/Fieldstone/Fieldstone_ORM.png,sha256=x0tUgUxjk53nsnleEy95tI1tUvFFQHGrB3pZVkd7b00,549202
49
+ ansys_pyensight_core-0.8.6.dist-info/LICENSE,sha256=qQWivZ12ETN5l3QxvTARY-QI5eoRRlyHdwLlAj0Bg5I,1089
50
+ ansys_pyensight_core-0.8.6.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
51
+ ansys_pyensight_core-0.8.6.dist-info/METADATA,sha256=Xh2Bmk_Z3r_fXeIox7euhPLxHvr5Tnys0D0CwT4Bq4k,11830
52
+ ansys_pyensight_core-0.8.6.dist-info/RECORD,,