ansys-pyensight-core 0.10.9__py3-none-any.whl → 0.10.12__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.

@@ -268,7 +268,7 @@ def find_app(ansys_installation: Optional[str] = None) -> Optional[str]:
268
268
  dirs_to_check = []
269
269
  if ansys_installation:
270
270
  # Given a different Ansys install
271
- local_tp = os.path.join(os.path.join(ansys_installation, "tp", "omni_viewer"))
271
+ local_tp = os.path.join(os.path.join(ansys_installation, "tp", "showcase"))
272
272
  if os.path.exists(local_tp):
273
273
  dirs_to_check.append(local_tp)
274
274
  # Dev Folder
@@ -277,7 +277,7 @@ def find_app(ansys_installation: Optional[str] = None) -> Optional[str]:
277
277
  dirs_to_check.append(local_dev_omni)
278
278
  if "PYENSIGHT_ANSYS_INSTALLATION" in os.environ:
279
279
  env_inst = os.environ["PYENSIGHT_ANSYS_INSTALLATION"]
280
- dirs_to_check.append(os.path.join(env_inst, "tp", "omni_viewer"))
280
+ dirs_to_check.append(os.path.join(env_inst, "tp", "showcase"))
281
281
 
282
282
  # Look for most recent Ansys install, 25.2 or later
283
283
  awp_roots = []
@@ -286,7 +286,7 @@ def find_app(ansys_installation: Optional[str] = None) -> Optional[str]:
286
286
  awp_roots.append(env_name)
287
287
  awp_roots.sort(reverse=True)
288
288
  for env_name in awp_roots:
289
- dirs_to_check.append(os.path.join(os.environ[env_name], "tp", "omni_viewer"))
289
+ dirs_to_check.append(os.path.join(os.environ[env_name], "tp", "showcase"))
290
290
 
291
291
  # check all the collected locations in order
292
292
  for install_dir in dirs_to_check:
@@ -38,10 +38,10 @@ import numpy
38
38
  import png
39
39
 
40
40
  try:
41
- from pxr import Gf, Kind, Sdf, Usd, UsdGeom, UsdLux, UsdShade
41
+ from pxr import Gf, Sdf, Usd, UsdGeom, UsdLux, UsdShade
42
42
  except ModuleNotFoundError:
43
- if sys.version_info.minor >= 13:
44
- warnings.warn("USD Export not supported for Python >= 3.13")
43
+ if sys.version_info.minor >= 14:
44
+ warnings.warn("USD Export not supported for Python >= 3.14")
45
45
  sys.exit(1)
46
46
  is_linux_arm64 = platform.system() == "Linux" and platform.machine() == "aarch64"
47
47
  if is_linux_arm64:
@@ -56,13 +56,15 @@ class OmniverseWrapper(object):
56
56
  destination: str = "",
57
57
  line_width: float = 0.0,
58
58
  ) -> None:
59
+ # File extension. For debugging, .usda is sometimes helpful.
60
+ self._ext = ".usd"
59
61
  self._cleaned_index = 0
60
62
  self._cleaned_names: dict = {}
61
63
  self._connectionStatusSubscription = None
62
64
  self._stage = None
63
65
  self._destinationPath: str = ""
64
66
  self._old_stages: list = []
65
- self._stagename: str = "dsg_scene.usd"
67
+ self._stagename: str = "dsg_scene" + self._ext
66
68
  self._live_edit: bool = live_edit
67
69
  if self._live_edit:
68
70
  self._stagename = "dsg_scene.live"
@@ -75,6 +77,8 @@ class OmniverseWrapper(object):
75
77
  self.destination = destination
76
78
 
77
79
  self._line_width = line_width
80
+ # Record the files per timestep, per mesh type. {part_name: {"surfaces": [], "lines": [], "points": []} }
81
+ self._time_files: dict = {}
78
82
 
79
83
  @property
80
84
  def destination(self) -> str:
@@ -148,7 +152,8 @@ class OmniverseWrapper(object):
148
152
  else:
149
153
  shutil.rmtree(stage, ignore_errors=True, onerror=None)
150
154
  except OSError:
151
- stages_unremoved.append(stage)
155
+ if not stage.endswith("_manifest" + self._ext):
156
+ stages_unremoved.append(stage)
152
157
  self._old_stages = stages_unremoved
153
158
 
154
159
  def create_new_stage(self) -> None:
@@ -276,8 +281,75 @@ class OmniverseWrapper(object):
276
281
  t = [t[0] * trans_convert, t[1] * trans_convert, t[2] * trans_convert]
277
282
  return s, r, t
278
283
 
284
+ # Common code to create the part manifest file and the file per timestep
285
+ def create_dsg_surfaces_file(
286
+ self,
287
+ file_url, # SdfPath, location on disk
288
+ part_path: str, # base path name, such as "/Root/Case_1/Isosurface_part"
289
+ verts,
290
+ normals,
291
+ conn,
292
+ tcoords,
293
+ diffuse,
294
+ variable,
295
+ mat_info,
296
+ is_manifest: bool,
297
+ ):
298
+ if is_manifest and file_url in self._old_stages:
299
+ return False
300
+ if not is_manifest and os.path.exists(file_url):
301
+ return False
302
+
303
+ stage = Usd.Stage.CreateNew(file_url)
304
+ UsdGeom.SetStageUpAxis(stage, self._up_axis)
305
+ UsdGeom.SetStageMetersPerUnit(stage, 1.0 / self._units_per_meter)
306
+ self._old_stages.append(file_url)
307
+
308
+ part_prim = stage.OverridePrim(part_path)
309
+
310
+ surfaces_prim = UsdGeom.Xform.Define(stage, part_path + "/surfaces")
311
+ surfaces_prim.AddXformOp(UsdGeom.XformOp.TypeTransform, UsdGeom.XformOp.PrecisionDouble)
312
+ mesh = UsdGeom.Mesh.Define(stage, str(surfaces_prim.GetPath()) + "/Mesh")
313
+ mesh.CreateDoubleSidedAttr().Set(True)
314
+ pt_attr = mesh.CreatePointsAttr()
315
+ if verts is not None:
316
+ pt_attr.Set(verts, 0)
317
+ norm_attr = mesh.CreateNormalsAttr()
318
+ if normals is not None:
319
+ norm_attr.Set(normals, 0)
320
+ fvc_attr = mesh.CreateFaceVertexCountsAttr()
321
+ fvi_attr = mesh.CreateFaceVertexIndicesAttr()
322
+ if conn is not None:
323
+ fvc_attr.Set([3] * (conn.size // 3), 0)
324
+ fvi_attr.Set(conn, 0)
325
+
326
+ primvarsAPI = UsdGeom.PrimvarsAPI(mesh)
327
+ texCoords = primvarsAPI.CreatePrimvar(
328
+ "st", Sdf.ValueTypeNames.TexCoord2fArray, UsdGeom.Tokens.varying
329
+ )
330
+ texCoords.SetInterpolation("vertex")
331
+ if tcoords is not None and variable is not None:
332
+ texCoords.Set(tcoords, 0)
333
+
334
+ stage.SetDefaultPrim(part_prim)
335
+ stage.SetStartTimeCode(0)
336
+ stage.SetEndTimeCode(0)
337
+
338
+ self.create_dsg_material(
339
+ stage,
340
+ mesh,
341
+ str(surfaces_prim.GetPath()),
342
+ diffuse=diffuse,
343
+ variable=variable,
344
+ mat_info=mat_info,
345
+ )
346
+
347
+ stage.Save()
348
+ return True
349
+
279
350
  def create_dsg_mesh_block(
280
351
  self,
352
+ part: Part,
281
353
  name,
282
354
  id,
283
355
  part_hash,
@@ -293,82 +365,174 @@ class OmniverseWrapper(object):
293
365
  first_timestep=False,
294
366
  mat_info={},
295
367
  ):
368
+ if self._stage is None:
369
+ return
370
+
296
371
  # 1D texture map for variables https://graphics.pixar.com/usd/release/tut_simple_shading.html
297
372
  # create the part usd object
298
- partname = self.clean_name(name + part_hash.hexdigest())
299
- stage_name = "/Parts/" + partname + ".usd"
300
- part_stage_url = self.stage_url(os.path.join("Parts", partname + ".usd"))
301
- part_stage = None
302
-
303
- if not os.path.exists(part_stage_url):
304
- part_stage = Usd.Stage.CreateNew(part_stage_url)
305
- UsdGeom.SetStageUpAxis(part_stage, self._up_axis)
306
- UsdGeom.SetStageMetersPerUnit(part_stage, 1.0 / self._units_per_meter)
307
- self._old_stages.append(part_stage_url)
308
- xform = UsdGeom.Xform.Define(part_stage, "/" + partname)
309
- mesh = UsdGeom.Mesh.Define(part_stage, "/" + partname + "/Mesh")
310
- # mesh.CreateDisplayColorAttr()
311
- mesh.CreateDoubleSidedAttr().Set(True)
312
- mesh.CreatePointsAttr(verts)
313
- mesh.CreateNormalsAttr(normals)
314
- mesh.CreateFaceVertexCountsAttr([3] * (conn.size // 3))
315
- mesh.CreateFaceVertexIndicesAttr(conn)
316
- if (tcoords is not None) and variable:
317
- primvarsAPI = UsdGeom.PrimvarsAPI(mesh)
318
- texCoords = primvarsAPI.CreatePrimvar(
319
- "st", Sdf.ValueTypeNames.TexCoord2fArray, UsdGeom.Tokens.varying
320
- )
321
- texCoords.Set(tcoords)
322
- texCoords.SetInterpolation("vertex")
323
- part_prim = part_stage.GetPrimAtPath("/" + partname)
324
- part_stage.SetDefaultPrim(part_prim)
373
+ part_base_name = self.clean_name(name)
374
+ partname = part_base_name + part_hash.hexdigest()
375
+ stage_name = "/Parts/" + partname + self._ext
376
+ part_stage_url = self.stage_url(os.path.join("Parts", partname + self._ext))
377
+
378
+ # Make the manifest file - once for all timesteps
379
+ part_manifest_url_relative = "./Parts/" + part_base_name + "_manifest" + self._ext
380
+ part_manifest_url = self.stage_url(part_manifest_url_relative)
381
+ created_file = self.create_dsg_surfaces_file(
382
+ part_manifest_url,
383
+ str(parent_prim.GetPath()),
384
+ None,
385
+ None,
386
+ None,
387
+ None,
388
+ diffuse,
389
+ variable,
390
+ mat_info,
391
+ True,
392
+ )
393
+ if created_file:
394
+ self._stage.GetRootLayer().subLayerPaths.append(part_manifest_url_relative)
395
+
396
+ # Make the per-timestep file
397
+ created_file = self.create_dsg_surfaces_file(
398
+ part_stage_url,
399
+ str(parent_prim.GetPath()),
400
+ verts,
401
+ normals,
402
+ conn,
403
+ tcoords,
404
+ diffuse,
405
+ variable,
406
+ mat_info,
407
+ False,
408
+ )
325
409
 
326
- # Currently, this will never happen, but it is a setup for rigid body transforms
327
- # At present, the group transforms have been cooked into the vertices so this is not needed
328
- matrixOp = xform.AddXformOp(
329
- UsdGeom.XformOp.TypeTransform, UsdGeom.XformOp.PrecisionDouble
330
- )
331
- matrixOp.Set(Gf.Matrix4d(*matrix).GetTranspose())
332
-
333
- self.create_dsg_material(
334
- part_stage,
335
- mesh,
336
- "/" + partname,
337
- diffuse=diffuse,
338
- variable=variable,
339
- mat_info=mat_info,
340
- )
410
+ # Glue the file into the main stage
411
+ path = parent_prim.GetPath().AppendChild("surfaces")
412
+ surfaces_prim = self._stage.OverridePrim(path)
413
+ self.add_timestep_valueclip(
414
+ part_base_name,
415
+ "surfaces",
416
+ surfaces_prim,
417
+ part_manifest_url_relative,
418
+ timeline,
419
+ stage_name,
420
+ )
341
421
 
342
- timestep_prim = self.add_timestep_group(parent_prim, timeline, first_timestep)
422
+ return part_stage_url
343
423
 
344
- # glue it into our stage
345
- path = timestep_prim.GetPath().AppendChild("part_ref_" + partname)
346
- part_ref = self._stage.OverridePrim(path)
347
- part_ref.GetReferences().AddReference("." + stage_name)
424
+ def get_time_files(self, part_name: str, mesh_type: str):
425
+ if part_name not in self._time_files:
426
+ self._time_files[part_name] = {"surfaces": [], "lines": [], "points": []}
427
+ return self._time_files[part_name][mesh_type]
348
428
 
349
- if part_stage is not None:
350
- part_stage.GetRootLayer().Save()
429
+ def add_timestep_valueclip(
430
+ self,
431
+ part_name: str,
432
+ mesh_type: str,
433
+ part_prim: UsdGeom.Xform,
434
+ manifest_path: str,
435
+ timeline: List[float],
436
+ stage_name: str,
437
+ ) -> None:
438
+ clips_api = Usd.ClipsAPI(part_prim)
439
+ asset_path = "." + stage_name
440
+
441
+ time_files = self.get_time_files(part_name, mesh_type)
442
+
443
+ if len(time_files) == 0 or time_files[-1][0] != asset_path:
444
+ time_files.append((asset_path, timeline[0]))
445
+ clips_api.SetClipAssetPaths([time_file[0] for time_file in time_files])
446
+ clips_api.SetClipActive(
447
+ [
448
+ (time_file[1] * self._time_codes_per_second, ii)
449
+ for ii, time_file in enumerate(time_files)
450
+ ]
451
+ )
452
+ clips_api.SetClipTimes(
453
+ [
454
+ (time_file[1] * self._time_codes_per_second, 0)
455
+ for ii, time_file in enumerate(time_files)
456
+ ]
457
+ )
458
+ clips_api.SetClipPrimPath(str(part_prim.GetPath()))
459
+ clips_api.SetClipManifestAssetPath(Sdf.AssetPath(manifest_path))
351
460
 
352
- return part_stage_url
461
+ # Common code to create the part manifest file and the file per timestep
462
+ def create_dsg_lines_file(
463
+ self,
464
+ file_url, # SdfPath, location on disk
465
+ part_path: str, # base path name, such as "/Root/Case_1/Isosurface_part"
466
+ verts,
467
+ width: float,
468
+ tcoords,
469
+ diffuse,
470
+ var_cmd,
471
+ mat_info,
472
+ is_manifest: bool,
473
+ ):
474
+ if is_manifest and file_url in self._old_stages:
475
+ return False
476
+ if not is_manifest and os.path.exists(file_url):
477
+ return False
478
+
479
+ stage = Usd.Stage.CreateNew(file_url)
480
+ UsdGeom.SetStageUpAxis(stage, self._up_axis)
481
+ UsdGeom.SetStageMetersPerUnit(stage, 1.0 / self._units_per_meter)
482
+ self._old_stages.append(file_url)
483
+
484
+ part_prim = stage.OverridePrim(part_path)
485
+
486
+ lines_prim = UsdGeom.Xform.Define(stage, part_path + "/lines")
487
+
488
+ lines_prim.AddXformOp(UsdGeom.XformOp.TypeTransform, UsdGeom.XformOp.PrecisionDouble)
489
+ lines = UsdGeom.BasisCurves.Define(stage, str(lines_prim.GetPath()) + "/Lines")
490
+ lines.CreateDoubleSidedAttr().Set(True)
491
+ pt_attr = lines.CreatePointsAttr()
492
+ vc_attr = lines.CreateCurveVertexCountsAttr()
493
+ if verts is not None:
494
+ pt_attr.Set(verts, 0)
495
+ vc_attr.Set([2] * (verts.size // 6), 0)
496
+ lines.CreatePurposeAttr().Set("render")
497
+ lines.CreateTypeAttr().Set("linear")
498
+ lines.CreateWidthsAttr([width])
499
+ lines.SetWidthsInterpolation("constant")
500
+
501
+ # Rounded endpoint are a primvar
502
+ primvarsAPI = UsdGeom.PrimvarsAPI(lines)
503
+ endCaps = primvarsAPI.CreatePrimvar(
504
+ "endcaps", Sdf.ValueTypeNames.Int, UsdGeom.Tokens.constant
505
+ )
506
+ endCaps.Set(2) # Rounded = 2
353
507
 
354
- def add_timestep_group(
355
- self, parent_prim: UsdGeom.Xform, timeline: List[float], first_timestep: bool
356
- ) -> UsdGeom.Xform:
357
- # add a layer in the group hierarchy for the timestep
358
- timestep_group_path = parent_prim.GetPath().AppendChild(
359
- self.clean_name("t" + str(timeline[0]), None)
508
+ prim = lines.GetPrim()
509
+ wireframe = width == 0.0
510
+ prim.CreateAttribute("omni:scene:visualization:drawWireframe", Sdf.ValueTypeNames.Bool).Set(
511
+ wireframe
360
512
  )
361
- timestep_prim = UsdGeom.Xform.Define(self._stage, timestep_group_path)
362
- visibility_attr = UsdGeom.Imageable(timestep_prim).GetVisibilityAttr()
363
- if first_timestep:
364
- visibility_attr.Set("inherited", Usd.TimeCode.EarliestTime())
365
- else:
366
- visibility_attr.Set("invisible", Usd.TimeCode.EarliestTime())
367
- visibility_attr.Set("inherited", timeline[0] * self._time_codes_per_second)
368
- # Final timestep has timeline[0]==timeline[1]. Leave final timestep visible.
369
- if timeline[0] < timeline[1]:
370
- visibility_attr.Set("invisible", timeline[1] * self._time_codes_per_second)
371
- return timestep_prim
513
+
514
+ if (tcoords is not None) and var_cmd:
515
+ primvarsAPI = UsdGeom.PrimvarsAPI(lines)
516
+ texCoords = primvarsAPI.CreatePrimvar(
517
+ "st", Sdf.ValueTypeNames.TexCoord2fArray, UsdGeom.Tokens.varying
518
+ )
519
+ if tcoords is not None and var_cmd is not None:
520
+ texCoords.Set(tcoords, 0)
521
+ texCoords.SetInterpolation("vertex")
522
+ stage.SetDefaultPrim(part_prim)
523
+ stage.SetStartTimeCode(0)
524
+ stage.SetEndTimeCode(0)
525
+
526
+ self.create_dsg_material(
527
+ stage,
528
+ lines,
529
+ str(lines_prim.GetPath()),
530
+ diffuse=diffuse,
531
+ variable=var_cmd,
532
+ mat_info=mat_info,
533
+ )
534
+ stage.Save()
535
+ return True
372
536
 
373
537
  def create_dsg_lines(
374
538
  self,
@@ -389,78 +553,97 @@ class OmniverseWrapper(object):
389
553
  # include the line width in the hash
390
554
  part_hash.update(str(self.line_width).encode("utf-8"))
391
555
 
392
- # 1D texture map for variables https://graphics.pixar.com/usd/release/tut_simple_shading.html
393
- # create the part usd object
394
- partname = self.clean_name(name + part_hash.hexdigest()) + "_l"
395
- stage_name = "/Parts/" + partname + ".usd"
396
- part_stage_url = self.stage_url(os.path.join("Parts", partname + ".usd"))
397
- part_stage = None
398
-
399
- var_cmd = variable
400
-
401
- if not os.path.exists(part_stage_url):
402
- part_stage = Usd.Stage.CreateNew(part_stage_url)
403
- UsdGeom.SetStageUpAxis(part_stage, self._up_axis)
404
- UsdGeom.SetStageMetersPerUnit(part_stage, 1.0 / self._units_per_meter)
405
- self._old_stages.append(part_stage_url)
406
- xform = UsdGeom.Xform.Define(part_stage, "/" + partname)
407
- lines = UsdGeom.BasisCurves.Define(part_stage, "/" + partname + "/Lines")
408
- lines.CreateDoubleSidedAttr().Set(True)
409
- lines.CreatePointsAttr(verts)
410
- lines.CreateCurveVertexCountsAttr([2] * (verts.size // 6))
411
- lines.CreatePurposeAttr().Set("render")
412
- lines.CreateTypeAttr().Set("linear")
413
- lines.CreateWidthsAttr([width])
414
- lines.SetWidthsInterpolation("constant")
415
- # Rounded endpoint are a primvar
416
- primvarsAPI = UsdGeom.PrimvarsAPI(lines)
417
- endCaps = primvarsAPI.CreatePrimvar(
418
- "endcaps", Sdf.ValueTypeNames.Int, UsdGeom.Tokens.constant
419
- )
420
- endCaps.Set(2) # Rounded = 2
421
-
422
- prim = lines.GetPrim()
423
- wireframe = width == 0.0
424
- prim.CreateAttribute(
425
- "omni:scene:visualization:drawWireframe", Sdf.ValueTypeNames.Bool
426
- ).Set(wireframe)
427
- if (tcoords is not None) and var_cmd:
428
- primvarsAPI = UsdGeom.PrimvarsAPI(lines)
429
- texCoords = primvarsAPI.CreatePrimvar(
430
- "st", Sdf.ValueTypeNames.TexCoord2fArray, UsdGeom.Tokens.varying
431
- )
432
- texCoords.Set(tcoords)
433
- texCoords.SetInterpolation("vertex")
434
- part_prim = part_stage.GetPrimAtPath("/" + partname)
435
- part_stage.SetDefaultPrim(part_prim)
556
+ part_base_name = self.clean_name(name) + "_l"
557
+ partname = part_base_name + part_hash.hexdigest()
558
+ stage_name = "/Parts/" + partname + self._ext
559
+ part_stage_url = self.stage_url(os.path.join("Parts", partname + self._ext))
560
+
561
+ # Make the manifest file - once for all timesteps
562
+ part_manifest_url_relative = "./Parts/" + part_base_name + "_manifest" + self._ext
563
+ part_manifest_url = self.stage_url(part_manifest_url_relative)
564
+ created_file = self.create_dsg_lines_file(
565
+ part_manifest_url,
566
+ str(parent_prim.GetPath()),
567
+ None,
568
+ width,
569
+ None,
570
+ diffuse,
571
+ variable,
572
+ mat_info,
573
+ True,
574
+ )
575
+ if created_file:
576
+ self._stage.GetRootLayer().subLayerPaths.append(part_manifest_url_relative)
577
+
578
+ # Make the per-timestep file
579
+ created_file = self.create_dsg_lines_file(
580
+ part_stage_url,
581
+ str(parent_prim.GetPath()),
582
+ verts,
583
+ width,
584
+ tcoords,
585
+ diffuse,
586
+ variable,
587
+ mat_info,
588
+ False,
589
+ )
436
590
 
437
- # Currently, this will never happen, but it is a setup for rigid body transforms
438
- # At present, the group transforms have been cooked into the vertices so this is not needed
439
- matrixOp = xform.AddXformOp(
440
- UsdGeom.XformOp.TypeTransform, UsdGeom.XformOp.PrecisionDouble
441
- )
442
- matrixOp.Set(Gf.Matrix4d(*matrix).GetTranspose())
443
-
444
- self.create_dsg_material(
445
- part_stage,
446
- lines,
447
- "/" + partname,
448
- diffuse=diffuse,
449
- variable=var_cmd,
450
- mat_info=mat_info,
451
- )
591
+ # Glue the file into the main stage
592
+ path = parent_prim.GetPath().AppendChild("lines")
593
+ lines_prim = self._stage.OverridePrim(path)
594
+ self.add_timestep_valueclip(
595
+ part_base_name, "lines", lines_prim, part_manifest_url_relative, timeline, stage_name
596
+ )
452
597
 
453
- timestep_prim = self.add_timestep_group(parent_prim, timeline, first_timestep)
598
+ return part_stage_url
454
599
 
455
- # glue it into our stage
456
- path = timestep_prim.GetPath().AppendChild("part_ref_" + partname)
457
- part_ref = self._stage.OverridePrim(path)
458
- part_ref.GetReferences().AddReference("." + stage_name)
600
+ # Common code to create the part manifest file and the file per timestep
601
+ def create_dsg_points_file(
602
+ self,
603
+ file_url, # SdfPath, location on disk
604
+ part_path: str, # base path name, such as "/Root/Case_1/Isosurface_part"
605
+ verts,
606
+ sizes,
607
+ colors,
608
+ default_size: float,
609
+ default_color,
610
+ is_manifest: bool,
611
+ ):
612
+ if is_manifest and file_url in self._old_stages:
613
+ return False
614
+ if not is_manifest and os.path.exists(file_url):
615
+ return False
616
+
617
+ stage = Usd.Stage.CreateNew(file_url)
618
+ UsdGeom.SetStageUpAxis(stage, self._up_axis)
619
+ UsdGeom.SetStageMetersPerUnit(stage, 1.0 / self._units_per_meter)
620
+ self._old_stages.append(file_url)
621
+
622
+ part_prim = stage.OverridePrim(part_path)
623
+ points = UsdGeom.Points.Define(stage, part_path + "/points")
624
+ pt_attr = points.CreatePointsAttr()
625
+ w_attr = points.CreateWidthsAttr()
626
+ if verts is not None:
627
+ pt_attr.Set(verts, 0)
628
+ if sizes is not None and sizes.size == (verts.size // 3):
629
+ w_attr.Set(sizes, 0)
630
+ else:
631
+ w_attr.Set([default_size] * (verts.size // 3), 0)
459
632
 
460
- if part_stage is not None:
461
- part_stage.GetRootLayer().Save()
633
+ colorAttr = points.GetPrim().GetAttribute("primvars:displayColor")
634
+ colorAttr.SetMetadata("interpolation", "vertex")
635
+ if verts is not None:
636
+ if colors is not None and colors.size == verts.size:
637
+ colorAttr.Set(colors, 0)
638
+ else:
639
+ colorAttr.Set([default_color[0:3]] * (verts.size // 3), 0)
462
640
 
463
- return part_stage_url
641
+ stage.SetDefaultPrim(part_prim)
642
+ stage.SetStartTimeCode(0)
643
+ stage.SetEndTimeCode(0)
644
+
645
+ stage.Save()
646
+ return True
464
647
 
465
648
  def create_dsg_points(
466
649
  self,
@@ -477,53 +660,45 @@ class OmniverseWrapper(object):
477
660
  timeline=[0.0, 0.0],
478
661
  first_timestep=False,
479
662
  ):
480
- # create the part usd object
481
- partname = self.clean_name(name + part_hash.hexdigest())
482
- stage_name = "/Parts/" + partname + ".usd"
483
- part_stage_url = self.stage_url(os.path.join("Parts", partname + ".usd"))
484
- part_stage = None
485
-
486
- if not os.path.exists(part_stage_url):
487
- part_stage = Usd.Stage.CreateNew(part_stage_url)
488
- UsdGeom.SetStageUpAxis(part_stage, self._up_axis)
489
- UsdGeom.SetStageMetersPerUnit(part_stage, 1.0 / self._units_per_meter)
490
- self._old_stages.append(part_stage_url)
491
- xform = UsdGeom.Xform.Define(part_stage, "/" + partname)
492
-
493
- points = UsdGeom.Points.Define(part_stage, "/" + partname + "/Points")
494
- # points.GetPointsAttr().Set(Vt.Vec3fArray(verts.tolist()))
495
- points.GetPointsAttr().Set(verts)
496
- if sizes is not None and sizes.size == (verts.size // 3):
497
- points.GetWidthsAttr().Set(sizes)
498
- else:
499
- points.GetWidthsAttr().Set([default_size] * (verts.size // 3))
500
-
501
- colorAttr = points.GetPrim().GetAttribute("primvars:displayColor")
502
- colorAttr.SetMetadata("interpolation", "vertex")
503
- if colors is not None and colors.size == verts.size:
504
- colorAttr.Set(colors)
505
- else:
506
- colorAttr.Set([default_color[0:3]] * (verts.size // 3))
507
-
508
- part_prim = part_stage.GetPrimAtPath("/" + partname)
509
- part_stage.SetDefaultPrim(part_prim)
510
-
511
- # Currently, this will never happen, but it is a setup for rigid body transforms
512
- # At present, the group transforms have been cooked into the vertices so this is not needed
513
- matrixOp = xform.AddXformOp(
514
- UsdGeom.XformOp.TypeTransform, UsdGeom.XformOp.PrecisionDouble
515
- )
516
- matrixOp.Set(Gf.Matrix4d(*matrix).GetTranspose())
517
-
518
- timestep_prim = self.add_timestep_group(parent_prim, timeline, first_timestep)
519
-
520
- # glue it into our stage
521
- path = timestep_prim.GetPath().AppendChild("part_ref_" + partname)
522
- part_ref = self._stage.OverridePrim(path)
523
- part_ref.GetReferences().AddReference("." + stage_name)
663
+ part_base_name = self.clean_name(name) + "_p"
664
+ partname = part_base_name + part_hash.hexdigest()
665
+ stage_name = "/Parts/" + partname + self._ext
666
+ part_stage_url = self.stage_url(os.path.join("Parts", partname + self._ext))
667
+
668
+ # Make the manifest file - once for all timesteps
669
+ part_manifest_url_relative = "./Parts/" + part_base_name + "_manifest" + self._ext
670
+ part_manifest_url = self.stage_url(part_manifest_url_relative)
671
+ created_file = self.create_dsg_points_file(
672
+ part_manifest_url,
673
+ str(parent_prim.GetPath()),
674
+ None,
675
+ None,
676
+ None,
677
+ default_size,
678
+ default_color,
679
+ True,
680
+ )
681
+ if created_file:
682
+ self._stage.GetRootLayer().subLayerPaths.append(part_manifest_url_relative)
683
+
684
+ # Make the per-timestep file
685
+ created_file = self.create_dsg_points_file(
686
+ part_stage_url,
687
+ str(parent_prim.GetPath()),
688
+ verts,
689
+ sizes,
690
+ colors,
691
+ default_size,
692
+ default_color,
693
+ False,
694
+ )
524
695
 
525
- if part_stage is not None:
526
- part_stage.GetRootLayer().Save()
696
+ # Glue the file into the main stage
697
+ path = parent_prim.GetPath().AppendChild("points")
698
+ points_prim = self._stage.OverridePrim(path)
699
+ self.add_timestep_valueclip(
700
+ part_base_name, "points", points_prim, part_manifest_url_relative, timeline, stage_name
701
+ )
527
702
 
528
703
  return part_stage_url
529
704
 
@@ -627,8 +802,10 @@ class OmniverseWrapper(object):
627
802
  if camera is not None:
628
803
  cam_name = "/Root/Cam"
629
804
  cam_prim = UsdGeom.Xform.Define(self._stage, cam_name)
630
- cam_pos = Gf.Vec3d(camera.lookfrom[0], camera.lookfrom[1], camera.lookfrom[2])
631
- target_pos = Gf.Vec3d(camera.lookat[0], camera.lookat[1], camera.lookat[2])
805
+ s = self._units_per_meter
806
+ cam_pos = Gf.Vec3d(camera.lookfrom[0], camera.lookfrom[1], camera.lookfrom[2]) * s
807
+ target_pos = Gf.Vec3d(camera.lookat[0], camera.lookat[1], camera.lookat[2]) * s
808
+
632
809
  up_vec = Gf.Vec3d(camera.upvector[0], camera.upvector[1], camera.upvector[2])
633
810
  cam_prim = self._stage.GetPrimAtPath(cam_name)
634
811
  geom_cam = UsdGeom.Camera(cam_prim)
@@ -647,7 +824,7 @@ class OmniverseWrapper(object):
647
824
  cam = geom_cam.GetCamera()
648
825
  # LOL, not sure why is might be correct, but so far it seems to work???
649
826
  cam.focalLength = camera.fieldofview
650
- dist = (target_pos - cam_pos).GetLength() * self._units_per_meter
827
+ dist = (target_pos - cam_pos).GetLength()
651
828
  cam.clippingRange = Gf.Range1f(0.1 * dist, 1000.0 * dist)
652
829
  look_at = Gf.Matrix4d()
653
830
  look_at.SetLookAt(cam_pos, target_pos, up_vec)
@@ -693,6 +870,7 @@ class OmniverseWrapper(object):
693
870
  )
694
871
  matrix_op.Set(Gf.Matrix4d(*matrix).GetTranspose())
695
872
  # Map kinds
873
+ """
696
874
  kind = Kind.Tokens.group
697
875
  if obj_type == "ENS_CASE":
698
876
  kind = Kind.Tokens.assembly
@@ -700,6 +878,7 @@ class OmniverseWrapper(object):
700
878
  kind = Kind.Tokens.component
701
879
  Usd.ModelAPI(group_prim).SetKind(kind)
702
880
  logging.info(f"Created group:'{name}' {str(obj_type)}")
881
+ """
703
882
  return group_prim
704
883
 
705
884
  def uploadMaterial(self):
@@ -732,6 +911,7 @@ class OmniverseUpdateHandler(UpdateHandler):
732
911
  self._group_prims: Dict[int, Any] = dict()
733
912
  self._root_prim = None
734
913
  self._sent_textures = False
914
+ self._case_xform_applied_to_camera = False
735
915
 
736
916
  def add_group(self, id: int, view: bool = False) -> None:
737
917
  super().add_group(id, view)
@@ -752,10 +932,11 @@ class OmniverseUpdateHandler(UpdateHandler):
752
932
  matrix = group.matrix4x4
753
933
  # Is this a "case" group (it will contain part of the camera view in the matrix)
754
934
  if obj_type == "ENS_CASE":
755
- if not self.session.vrmode:
935
+ if not self.session.vrmode and not self._case_xform_applied_to_camera:
756
936
  # if in camera mode, we need to update the camera matrix so we can
757
937
  # use the identity matrix on this group. The camera should have been
758
938
  # created in the "view" handler
939
+ self._case_xform_applied_to_camera = True
759
940
  cam_name = "/Root/Cam"
760
941
  cam_prim = self._omni._stage.GetPrimAtPath(cam_name) # type: ignore
761
942
  geom_cam = UsdGeom.Camera(cam_prim)
@@ -763,9 +944,12 @@ class OmniverseUpdateHandler(UpdateHandler):
763
944
  cam = geom_cam.GetCamera()
764
945
  c = cam.transform
765
946
  m = Gf.Matrix4d(*matrix).GetTranspose()
947
+ s = self._omni._units_per_meter
948
+ trans = m.GetRow(3)
949
+ trans = Gf.Vec4d(trans[0] * s, trans[1] * s, trans[2] * s, trans[3])
950
+ m.SetRow(3, trans)
766
951
  # move the model transform to the camera transform
767
- sc = Gf.Matrix4d(self._omni._units_per_meter)
768
- cam.transform = c * m.GetInverse() * sc
952
+ cam.transform = c * m.GetInverse()
769
953
 
770
954
  # Determine if the camera is principally more Y, or Z up. X up not supported.
771
955
  # Omniverse' built in navigator tries to keep this direction up
@@ -874,6 +1058,7 @@ class OmniverseUpdateHandler(UpdateHandler):
874
1058
  has_triangles = True
875
1059
  # Generate the mesh block
876
1060
  _ = self._omni.create_dsg_mesh_block(
1061
+ part,
877
1062
  name,
878
1063
  obj_id,
879
1064
  part.hash,
@@ -980,6 +1165,7 @@ class OmniverseUpdateHandler(UpdateHandler):
980
1165
  self._omni.clear_cleaned_names()
981
1166
  # clear the group Omni prims list
982
1167
  self._group_prims = dict()
1168
+ self._case_xform_applied_to_camera = False
983
1169
 
984
1170
  self._omni.create_new_stage()
985
1171
  self._root_prim = self._omni.create_dsg_root()
@@ -71,10 +71,11 @@ class _Simba:
71
71
  self.ensight.annotation.axis_global("off")
72
72
  self.ensight.annotation.axis_local("off")
73
73
  self.ensight.annotation.axis_model("off")
74
+ self.ensight.view_transf.zclip_float("OFF")
74
75
 
75
76
  def get_center_of_rotation(self):
76
77
  """Get EnSight center of rotation."""
77
- return self.ensight.objs.core.VPORTS[0].TRANSFORMCENTER
78
+ return self.ensight.objs.core.VPORTS[0].TRANSFORMCENTER.copy()
78
79
 
79
80
  def auto_scale(self):
80
81
  """Auto scale view."""
@@ -94,8 +95,7 @@ class _Simba:
94
95
  self.views.set_view_direction(
95
96
  1, 1, 1, perspective=self.ensight.objs.core.vports[0].PERSPECTIVE
96
97
  )
97
- self.auto_scale()
98
- return self.get_camera()
98
+ return self.auto_scale()
99
99
 
100
100
  def get_camera(self):
101
101
  """Get EnSight camera settings in VTK format."""
@@ -107,6 +107,7 @@ class _Simba:
107
107
  # if the vport is in orthographic mode. If not, it is defined as the
108
108
  # inverge of the tangent of half of the field of view
109
109
  parallel_scale = parallel_scale
110
+ clipping_range = vport.ZCLIPLIMITS
110
111
  return {
111
112
  "orthographic": not vport.PERSPECTIVE,
112
113
  "view_up": view_up,
@@ -119,6 +120,8 @@ class _Simba:
119
120
  "reset_parallel_scale": self._original_parallel_scale,
120
121
  "reset_view_up": self._original_view_up,
121
122
  "reset_view_angle": self._original_view_angle,
123
+ "near_plane": clipping_range[0],
124
+ "far_plane": clipping_range[1],
122
125
  }
123
126
 
124
127
  @staticmethod
@@ -208,8 +211,56 @@ class _Simba:
208
211
  parallel_scale = 1 / data[9]
209
212
  return camera_position, focal_point, self.views._normalize_vector(view_up), parallel_scale
210
213
 
214
+ def get_camera_axes(self):
215
+ """
216
+ Returns the camera's local axes: right, up, and forward vectors.
217
+ These are useful for applying transformations in view space.
218
+
219
+ Parameters:
220
+ camera (dict): A dictionary with keys 'position', 'focal_point', and 'view_up'.
221
+
222
+ Returns:
223
+ right (np.ndarray): Right vector (X axis in view space).
224
+ up (np.ndarray): Up vector (Y axis in view space).
225
+ forw ard (np.ndarray): Forward vector (Z axis in view space, pointing from position to focal point).
226
+ """
227
+ camera = self.get_camera()
228
+ position = np.array(camera["position"])
229
+ focal_point = np.array(camera["focal_point"])
230
+ view_up = np.array(camera["view_up"])
231
+
232
+ # Forward vector: from camera position to focal point
233
+ forward = focal_point - position
234
+ forward /= np.linalg.norm(forward)
235
+
236
+ # Right vector: cross product of forward and view_up
237
+ right = np.cross(forward, view_up)
238
+ right /= np.linalg.norm(right)
239
+
240
+ # Recompute up vector to ensure orthogonality
241
+ up = np.cross(right, forward)
242
+ up /= np.linalg.norm(up)
243
+
244
+ return right, up, forward
245
+
246
+ def _arbitrary_orthogonal(self, v):
247
+ if abs(v[0]) < abs(v[1]) and abs(v[0]) < abs(v[2]):
248
+ return self.normalize(np.array(self.views._cross_product(v.tolist(), [1, 0, 0])))
249
+ elif abs(v[1]) < abs(v[2]):
250
+ return self.normalize(np.array(self.views._cross_product(v.tolist(), [0, 1, 0])))
251
+ return self.normalize(np.array(self.views._cross_product(v.tolist(), [0, 0, 1])))
252
+
211
253
  def set_camera(
212
- self, orthographic, view_up=None, position=None, focal_point=None, view_angle=None, pan=None
254
+ self,
255
+ orthographic,
256
+ view_up=None,
257
+ position=None,
258
+ focal_point=None,
259
+ view_angle=None,
260
+ pan=None,
261
+ mousex=None,
262
+ mousey=None,
263
+ invert_y=False,
213
264
  ):
214
265
  """Set the EnSight camera settings from the VTK input."""
215
266
  self.ensight.view_transf.function("global")
@@ -219,21 +270,65 @@ class _Simba:
219
270
  vport = self.ensight.objs.core.VPORTS[0]
220
271
  if view_angle:
221
272
  vport.PERSPECTIVEANGLE = view_angle / 2
222
-
223
273
  if view_up and position and focal_point:
224
- if not pan:
225
- q_current = self.normalize(np.array(vport.ROTATION.copy()))
226
- q_target = self.normalize(
227
- self.compute_model_rotation_quaternion(position, focal_point, view_up)
228
- )
229
- q_relative = self.quaternion_multiply(
230
- q_target, np.array([-q_current[0], -q_current[1], -q_current[2], q_current[3]])
231
- )
232
- angles = self.quaternion_to_euler(q_relative)
233
- self.ensight.view_transf.rotate(*angles)
234
- else:
235
- self.ensight.view_transf.translate(*pan)
274
+ # Compute relative rotation
275
+ q_current = self.normalize(np.array(vport.ROTATION.copy()))
276
+ q_target = self.normalize(
277
+ self.compute_model_rotation_quaternion(position, focal_point, view_up)
278
+ )
279
+ q_relative = self.quaternion_multiply(
280
+ q_target, np.array([-q_current[0], -q_current[1], -q_current[2], q_current[3]])
281
+ )
282
+ angles = self.quaternion_to_euler(q_relative)
283
+ self.ensight.view_transf.rotate(*angles)
284
+ # Decompose eventual translation from rotation
285
+ current_camera = self.get_camera()
286
+ center = vport.TRANSFORMCENTER.copy()
287
+ pos0, focal0, up0 = map(
288
+ np.array,
289
+ [
290
+ current_camera["position"],
291
+ current_camera["focal_point"],
292
+ current_camera["view_up"],
293
+ ],
294
+ )
295
+ pos1, focal1, up1 = map(np.array, [position, focal_point, view_up])
296
+ dir0 = self.normalize(focal0 - pos0)
297
+ right0 = np.cross(dir0, up0)
298
+ norm = np.linalg.norm(right0)
299
+ if norm <= 1e-6:
300
+ right0 = self._arbitrary_orthogonal(dir0)
301
+ up0n = np.cross(right0, dir0)
302
+ dir1 = self.normalize(focal1 - pos1)
303
+ right1 = np.cross(dir1, up1)
304
+ norm = np.linalg.norm(right1)
305
+ if norm <= 1e-6:
306
+ right1 = self._arbitrary_orthogonal(dir1)
307
+ up1n = np.cross(right1, dir1)
308
+ # Now that orthonormal basis have been computed for the
309
+ # old and new camera, one can compute the rotation matrix
310
+ # that takes the old camera to the new one
311
+ A = np.stack([right0, up0n, dir0], axis=1)
312
+ B = np.stack([right1, up1n, dir1], axis=1)
313
+ R = B @ A.T
314
+ # Compute the rotated only vector from the old camera
315
+ # to the new camera direction
316
+ rotatedDistance = R @ (pos0 - center) + center
317
+ # Compute the view matrix for the rotated camera axes
318
+ rotated_focal = focal0 + (rotatedDistance - pos0)
319
+ rotated_dir = self.normalize(rotated_focal - rotatedDistance)
320
+ rotated_right = np.cross(rotated_dir, up0)
321
+ if np.linalg.norm(rotated_right) <= 1e-6:
322
+ rotated_right = self._arbitrary_orthogonal(rotated_dir)
323
+ rotated_up = np.cross(rotated_right, rotated_dir)
324
+ # Compute the world coordinates translation and move it to
325
+ # view space
326
+ offset = pos1 - rotatedDistance
327
+ translation = -np.stack([rotated_right, rotated_up, rotated_dir]) @ offset
328
+ self.ensight.view_transf.translate(translation[0], translation[1], 0)
329
+
236
330
  self.render()
331
+ return self.get_camera()
237
332
 
238
333
  def set_perspective(self, value):
239
334
  self.ensight.view_transf.function("global")
@@ -265,7 +360,37 @@ class _Simba:
265
360
  self.ensight.render()
266
361
  self.ensight.refresh(1)
267
362
 
268
- def drag_allowed(self, mousex, mousey, invert_y=False):
363
+ def _probe_setup(self, part_obj, get_probe_data=False):
364
+ self.ensight.query_interact.number_displayed(100)
365
+ self.ensight.query_interact.query("surface")
366
+ self.ensight.query_interact.display_id("OFF")
367
+ self.ensight.query_interact.label_always_on_top("ON")
368
+ self.ensight.query_interact.marker_size_normalized(2)
369
+ if get_probe_data:
370
+ variable_string = """Coordinates 'X' 'Y' 'Z'"""
371
+ variable_list = [variable_string]
372
+ variable_name = part_obj.COLORBYPALETTE
373
+ if variable_name:
374
+ if isinstance(variable_name, str):
375
+ variable_list.append(variable_name)
376
+ else:
377
+ if isinstance(variable_name, list):
378
+ if variable_name[0]:
379
+ variable_name = variable_name[0].DESCRIPTION
380
+ variable_list.append(variable_name)
381
+ else:
382
+ variable_name = None
383
+ if isinstance(self.ensight, ModuleType):
384
+ self.ensight.query_interact.select_varname_begin(*variable_list)
385
+ else:
386
+ command = "ensight.query_interact.select_varname_begin("
387
+ for var in variable_list:
388
+ command += var + ","
389
+ command = command[:-1] + ")"
390
+ self.ensight._session.cmd(command)
391
+ self.render()
392
+
393
+ def drag_allowed(self, mousex, mousey, invert_y=False, probe=False, get_probe_data=False):
269
394
  """Return True if the picked object is allowed dragging in the interactor."""
270
395
  mousex = int(mousex)
271
396
  mousey = int(mousey)
@@ -277,8 +402,14 @@ class _Simba:
277
402
  part_id, tool_id = self.ensight._session.cmd(
278
403
  f"ensight.objs.core.VPORTS[0].simba_what_is_picked({mousex}, {mousey}, {invert_y})"
279
404
  )
405
+ coords = [None, None, None]
406
+ if probe:
407
+ screen_to_world = self.screen_to_world(
408
+ mousex=mousex, mousey=mousey, invert_y=invert_y, set_center=False
409
+ )
410
+ coords = screen_to_world["model_point"]
280
411
  if tool_id > -1:
281
- return True
412
+ return True, coords[0], coords[1], coords[2], False
282
413
  part_types_allowed = [
283
414
  self.ensight.objs.enums.PART_CLIP_PLANE,
284
415
  self.ensight.objs.enums.PART_ISO_SURFACE,
@@ -286,8 +417,22 @@ class _Simba:
286
417
  ]
287
418
  if part_id > -1:
288
419
  part_obj = self.ensight.objs.core.PARTS.find(part_id, "PARTNUMBER")[0]
289
- return part_obj.PARTTYPE in part_types_allowed
290
- return False
420
+ if probe:
421
+ width, height = tuple(self.ensight.objs.core.WINDOWSIZE)
422
+ if invert_y:
423
+ mousey = height - mousey
424
+ self.ensight.query_interact.number_displayed(100)
425
+ self.ensight.query_interact.query("surface")
426
+ self.ensight.query_interact.display_id("OFF")
427
+ self.ensight.query_interact.create(mousex / width, mousey / height)
428
+ self._probe_setup(part_obj, get_probe_data=get_probe_data)
429
+ return part_obj.PARTTYPE in part_types_allowed, coords[0], coords[1], coords[2], True
430
+ if (
431
+ get_probe_data and self.ensight.objs.core.PROBES[0].PROBE_DATA
432
+ ): # In case we have picked a probe point
433
+ for part in self.ensight.objs.core.PARTS:
434
+ self._probe_setup(part, get_probe_data=get_probe_data)
435
+ return False, coords[0], coords[1], coords[2], False
291
436
 
292
437
 
293
438
  class Views:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ansys-pyensight-core
3
- Version: 0.10.9
3
+ Version: 0.10.12
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>
@@ -25,7 +25,7 @@ Requires-Dist: numpy>=1.21.0,<3
25
25
  Requires-Dist: Pillow>=9.3.0
26
26
  Requires-Dist: pypng>=0.0.20
27
27
  Requires-Dist: psutil>=5.9.2
28
- Requires-Dist: usd-core==24.8; python_version < '3.13' and platform_machine != 'aarch64'
28
+ Requires-Dist: usd-core==25.8; platform_machine != 'aarch64'
29
29
  Requires-Dist: pygltflib>=1.16.2
30
30
  Requires-Dist: grpcio<1.68.0
31
31
  Requires-Dist: build>=0.10.0 ; extra == "dev"
@@ -46,7 +46,7 @@ Requires-Dist: sphinxcontrib.jquery==4.1 ; extra == "doc"
46
46
  Requires-Dist: sphinxcontrib-openapi==0.8.4 ; extra == "doc"
47
47
  Requires-Dist: coverage-badge==1.1.2 ; extra == "doc"
48
48
  Requires-Dist: sphinxcontrib-video==0.2.1 ; extra == "doc"
49
- Requires-Dist: usd-core>=24.8 ; extra == "doc"
49
+ Requires-Dist: usd-core>=25.8 ; extra == "doc"
50
50
  Requires-Dist: pygltflib>=1.16.2 ; extra == "doc"
51
51
  Requires-Dist: pytest==8.3.5 ; extra == "tests"
52
52
  Requires-Dist: pytest-cov==5.0.0 ; extra == "tests"
@@ -20,18 +20,18 @@ ansys/pyensight/core/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
20
20
  ansys/pyensight/core/utils/adr.py,sha256=XslZhlwcrSGzOlnhzprOv3ju_ppxxsWBjCnQL5KiNms,3570
21
21
  ansys/pyensight/core/utils/dsg_server.py,sha256=2jCPhOplPrlDaQNSKSk9qo7bEgfcrhx0rHS_cqW2zAY,47003
22
22
  ansys/pyensight/core/utils/export.py,sha256=GC0NbVl0_CXvUUfkbJl49yjTsP_58bJZyjE95q6ATUo,22604
23
- ansys/pyensight/core/utils/omniverse.py,sha256=Xnjw8XiIzTCOHKvpb7dH-P3ObA3dQHJvxXEsrRt6XvI,24738
23
+ ansys/pyensight/core/utils/omniverse.py,sha256=yxLeEX6J1D_NwWSn-sm_C6-VYiLvYehHCbj1b19BxNI,24729
24
24
  ansys/pyensight/core/utils/omniverse_cli.py,sha256=ujoBbBGMYsYUn83nrk2dFkOd7kn7-6cs7ljBmmSXodw,20578
25
- ansys/pyensight/core/utils/omniverse_dsg_server.py,sha256=MuHVurd8zaSIsQkvrY94X_IJSldFShnzEoGItjvZTTw,41067
25
+ ansys/pyensight/core/utils/omniverse_dsg_server.py,sha256=KPsnHstndXiv9jePGW3qnqqjMycKwZUL2vH7Thvq-wA,45547
26
26
  ansys/pyensight/core/utils/omniverse_glb_server.py,sha256=dx2cfR036d3DY6meooNfLZOQpOMaiaLKqBjztpew2_Q,32167
27
27
  ansys/pyensight/core/utils/parts.py,sha256=222XFRCjLgH7hho-cK9JrGCg3-KlTf54KIgc7y50sTE,52173
28
28
  ansys/pyensight/core/utils/query.py,sha256=OXKDbf1sOTX0sUvtKcp64LhVl-BcrEsE43w8uMxLOYI,19828
29
29
  ansys/pyensight/core/utils/readers.py,sha256=_IluAWz8mmoe5SM3hAewHIqlhtKMfEqrUJoQOlJ4U4I,12138
30
30
  ansys/pyensight/core/utils/support.py,sha256=QI3z9ex7zJxjFbkCPba9DWqWgPFIThORqr0nvRfVjuc,4089
31
31
  ansys/pyensight/core/utils/variables.py,sha256=ZUiJdDIeRcowrnLXaJQqGwA0RbrfXhc1s4o4v9A4PiY,95133
32
- ansys/pyensight/core/utils/views.py,sha256=YyTv7F7g6ixf8xFf0fUKXe7s1pbSgbXGzKrFNIMUH5A,22845
32
+ ansys/pyensight/core/utils/views.py,sha256=qkc_xPZ4Ea8dof6eqRwOd6dPrbruDTODoFzlnczpJGU,29578
33
33
  ansys/pyensight/core/utils/resources/Materials/000_sky.exr,sha256=xAR1gFd2uxPZDnvgfegdhEhRaqKtZldQDiR_-1rHKO0,8819933
34
- ansys_pyensight_core-0.10.9.dist-info/licenses/LICENSE,sha256=K6LiJHOa9IbWFelXmXNRzFr3zG45SOGZIN7vdLdURGU,1097
35
- ansys_pyensight_core-0.10.9.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
36
- ansys_pyensight_core-0.10.9.dist-info/METADATA,sha256=yV4oBGTFEw5MiNzPVnfN6kkrY9NXQHkJpeAb1X7KV_I,12228
37
- ansys_pyensight_core-0.10.9.dist-info/RECORD,,
34
+ ansys_pyensight_core-0.10.12.dist-info/licenses/LICENSE,sha256=K6LiJHOa9IbWFelXmXNRzFr3zG45SOGZIN7vdLdURGU,1097
35
+ ansys_pyensight_core-0.10.12.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
36
+ ansys_pyensight_core-0.10.12.dist-info/METADATA,sha256=-wrfz96hNIMWHitCBnMbeldilHN4Nfi_NWL4gTpJ8qA,12201
37
+ ansys_pyensight_core-0.10.12.dist-info/RECORD,,