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.
- ansys/pyensight/core/exts/ansys.geometry.service/ansys/geometry/service/__init__.py +1 -0
- ansys/pyensight/core/exts/ansys.geometry.service/ansys/geometry/service/extension.py +407 -0
- ansys/pyensight/core/exts/ansys.geometry.service/config/extension.toml +59 -0
- ansys/pyensight/core/exts/ansys.geometry.service/data/icon.png +0 -0
- ansys/pyensight/core/exts/ansys.geometry.service/data/preview.png +0 -0
- ansys/pyensight/core/exts/ansys.geometry.service/docs/CHANGELOG.md +8 -0
- ansys/pyensight/core/exts/ansys.geometry.service/docs/README.md +13 -0
- ansys/pyensight/core/exts/ansys.geometry.service/docs/index.rst +18 -0
- ansys/pyensight/core/exts/ansys.geometry.serviceui/ansys/geometry/serviceui/__init__.py +1 -0
- ansys/pyensight/core/exts/ansys.geometry.serviceui/ansys/geometry/serviceui/extension.py +193 -0
- ansys/pyensight/core/exts/ansys.geometry.serviceui/config/extension.toml +49 -0
- ansys/pyensight/core/exts/ansys.geometry.serviceui/data/icon.png +0 -0
- ansys/pyensight/core/exts/ansys.geometry.serviceui/data/preview.png +0 -0
- ansys/pyensight/core/exts/ansys.geometry.serviceui/docs/CHANGELOG.md +8 -0
- ansys/pyensight/core/exts/ansys.geometry.serviceui/docs/README.md +13 -0
- ansys/pyensight/core/exts/ansys.geometry.serviceui/docs/index.rst +18 -0
- ansys/pyensight/core/launcher.py +36 -1
- ansys/pyensight/core/locallauncher.py +3 -1
- ansys/pyensight/core/utils/dsg_server.py +36 -11
- ansys/pyensight/core/utils/omniverse.py +151 -95
- ansys/pyensight/core/utils/omniverse_dsg_server.py +91 -37
- {ansys_pyensight_core-0.8.4.dist-info → ansys_pyensight_core-0.8.6.dist-info}/METADATA +1 -1
- ansys_pyensight_core-0.8.6.dist-info/RECORD +52 -0
- ansys_pyensight_core-0.8.4.dist-info/RECORD +0 -36
- {ansys_pyensight_core-0.8.4.dist-info → ansys_pyensight_core-0.8.6.dist-info}/LICENSE +0 -0
- {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,
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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.
|
|
212
|
+
if self.is_running_omniverse():
|
|
159
213
|
raise RuntimeError("An Omniverse server connection is already active.")
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
"
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
]
|
|
177
|
-
|
|
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.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
233
|
-
|
|
282
|
+
update_cmd = "dynamicscenegraph://localhost/client/update"
|
|
283
|
+
if temporal:
|
|
284
|
+
update_cmd += "?timesteps=1"
|
|
234
285
|
self._check_modules()
|
|
235
|
-
if not self.
|
|
286
|
+
if not self.is_running_omniverse():
|
|
236
287
|
raise RuntimeError("No Omniverse server connection is currently active.")
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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[(
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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.
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
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
|
-
|
|
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
|
-
|
|
628
|
-
# Create the root group/camera
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
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.
|
|
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.
|
|
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:
|
|
@@ -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,,
|