orca-lab 25.9.0__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.
Files changed (72) hide show
  1. orca_lab-25.9.0.dist-info/METADATA +181 -0
  2. orca_lab-25.9.0.dist-info/RECORD +72 -0
  3. orca_lab-25.9.0.dist-info/WHEEL +5 -0
  4. orca_lab-25.9.0.dist-info/licenses/LICENSE +22 -0
  5. orca_lab-25.9.0.dist-info/top_level.txt +1 -0
  6. orcalab/__init__.py +0 -0
  7. orcalab/actor.py +146 -0
  8. orcalab/application_bus.py +17 -0
  9. orcalab/asset_service.py +50 -0
  10. orcalab/asset_service_bus.py +22 -0
  11. orcalab/asset_sync_service.py +389 -0
  12. orcalab/asset_sync_ui.py +212 -0
  13. orcalab/assets/assets.qrc +11 -0
  14. orcalab/assets/gen.py +7 -0
  15. orcalab/assets/icons/ic_fluent_add_20_filled.svg +3 -0
  16. orcalab/assets/icons/ic_fluent_eye_20_regular.svg +3 -0
  17. orcalab/assets/icons/ic_fluent_eye_off_20_regular.svg +3 -0
  18. orcalab/assets/icons/ic_fluent_filter_20_filled.svg +3 -0
  19. orcalab/assets/icons/ic_fluent_lock_closed_20_regular.svg +3 -0
  20. orcalab/assets/icons/ic_fluent_lock_open_20_regular.svg +3 -0
  21. orcalab/assets/icons/ic_fluent_pause_20_filled.svg +3 -0
  22. orcalab/assets/icons/ic_fluent_play_20_filled_green.svg +3 -0
  23. orcalab/assets/icons/ic_fluent_stop_20_filled_red.svg +3 -0
  24. orcalab/assets/rc_assets.py +302 -0
  25. orcalab/auth_service.py +242 -0
  26. orcalab/config_service.py +163 -0
  27. orcalab/copilot/__init__.py +10 -0
  28. orcalab/copilot/service.py +456 -0
  29. orcalab/event_bus.py +105 -0
  30. orcalab/local_scene.py +223 -0
  31. orcalab/math.py +334 -0
  32. orcalab/path.py +101 -0
  33. orcalab/project_util.py +152 -0
  34. orcalab/protos/__init__.py +3 -0
  35. orcalab/protos/edit_service.proto +265 -0
  36. orcalab/protos/edit_service_pb2.py +134 -0
  37. orcalab/protos/edit_service_pb2_grpc.py +1043 -0
  38. orcalab/protos/generate_proto.py +32 -0
  39. orcalab/protos/url_service.proto +21 -0
  40. orcalab/protos/url_service_pb2.py +42 -0
  41. orcalab/protos/url_service_pb2_grpc.py +97 -0
  42. orcalab/pyside_util.py +27 -0
  43. orcalab/remote_scene.py +688 -0
  44. orcalab/scene_edit_bus.py +219 -0
  45. orcalab/scene_edit_service.py +246 -0
  46. orcalab/sim_process.py +28 -0
  47. orcalab/token_storage.py +107 -0
  48. orcalab/ui/__init__.py +0 -0
  49. orcalab/ui/actor_editor.py +200 -0
  50. orcalab/ui/actor_outline.py +320 -0
  51. orcalab/ui/actor_outline_model.py +394 -0
  52. orcalab/ui/asset_browser.py +245 -0
  53. orcalab/ui/auth_window.py +191 -0
  54. orcalab/ui/copilot.py +580 -0
  55. orcalab/ui/float_edit.py +141 -0
  56. orcalab/ui/launch_dialog.py +280 -0
  57. orcalab/ui/main_window.py +883 -0
  58. orcalab/ui/rename_dialog.py +84 -0
  59. orcalab/ui/sync_progress_window.py +358 -0
  60. orcalab/ui/terminal_widget.py +308 -0
  61. orcalab/ui/tool_bar.py +43 -0
  62. orcalab/ui/transform_edit.py +131 -0
  63. orcalab/ui/viewport.py +64 -0
  64. orcalab/undo_service/command.py +90 -0
  65. orcalab/undo_service/undo_service.py +171 -0
  66. orcalab/undo_service/undo_service_bus.py +48 -0
  67. orcalab/url_service/__init__.py +0 -0
  68. orcalab/url_service/url_handler.py +57 -0
  69. orcalab/url_service/url_service.py +51 -0
  70. orcalab/url_service/url_util.py +58 -0
  71. orcalab/url_service/url_util_linux.py +74 -0
  72. orcalab/url_service/url_util_windows.py +67 -0
@@ -0,0 +1,181 @@
1
+ Metadata-Version: 2.4
2
+ Name: orca-lab
3
+ Version: 25.9.0
4
+ Summary: OrcaLab - Cloud-native robotics simulation platform with advanced UI and asset management
5
+ Author-email: 松应科技 <huangwei@orca3d.cn>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/openverse-orca/OrcaLab
8
+ Project-URL: Documentation, https://github.com/openverse-orca/OrcaLab
9
+ Project-URL: Repository, https://github.com/openverse-orca/OrcaLab
10
+ Project-URL: Bug Tracker, https://github.com/openverse-orca/OrcaLab/issues
11
+ Keywords: robotics,simulation,ui,asset-management,orca,pyside
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
+ Classifier: Topic :: Software Development :: User Interfaces
19
+ Requires-Python: >=3.12
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: orca-gym
23
+ Requires-Dist: numpy>=2.0.0
24
+ Requires-Dist: scipy
25
+ Requires-Dist: scipy-stubs
26
+ Requires-Dist: grpcio==1.66.1
27
+ Requires-Dist: grpcio-tools==1.66.1
28
+ Requires-Dist: pyside6==6.9.2
29
+ Requires-Dist: aiohttp
30
+ Requires-Dist: aiofiles
31
+ Requires-Dist: qasync
32
+ Requires-Dist: psutil
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest; extra == "dev"
35
+ Requires-Dist: pytest-cov; extra == "dev"
36
+ Requires-Dist: flake8; extra == "dev"
37
+ Requires-Dist: black; extra == "dev"
38
+ Requires-Dist: mypy; extra == "dev"
39
+ Dynamic: license-file
40
+
41
+ # OrcaLab
42
+
43
+ OrcaLab is a front-end of OrcaGym. It provides a user-interface for scene assembling and simulation.
44
+
45
+ ## Features
46
+
47
+ - TODO
48
+
49
+ ## Requirements
50
+
51
+ - Python 3.12 or higher
52
+ - [OrcaGym](https://github.com/your-org/OrcaGym) (required dependency)
53
+ - Other dependencies listed in `pyproject.toml`
54
+
55
+ ## Development Requirements
56
+
57
+ For building and releasing packages, the following pip packages are required:
58
+
59
+ ### Core Build Tools
60
+ ```bash
61
+ pip install build twine wheel setuptools
62
+ ```
63
+
64
+ ### Development Tools (Optional)
65
+ ```bash
66
+ pip install pytest pytest-cov flake8 black mypy
67
+ ```
68
+
69
+ ### Make Commands and Required Packages
70
+
71
+ The project includes a `Makefile` with various commands. Here are the required packages for each command:
72
+
73
+ | Make Command | Required pip packages | Description |
74
+ |-------------|----------------------|-------------|
75
+ | `make build` | `build`, `setuptools`, `wheel` | Build distribution packages |
76
+ | `make check` | `twine` | Check package quality |
77
+ | `make test-install` | `build`, `setuptools`, `wheel` | Test local installation |
78
+ | `make test-install-testpypi` | `build`, `setuptools`, `wheel` | Test TestPyPI installation |
79
+ | `make test-install-pypi` | `build`, `setuptools`, `wheel` | Test PyPI installation |
80
+ | `make release-test` | `build`, `twine`, `setuptools`, `wheel` | Release to TestPyPI |
81
+ | `make release-prod` | `build`, `twine`, `setuptools`, `wheel` | Release to PyPI |
82
+ | `make bump-version` | None (uses sed) | Bump version number |
83
+ | `make setup-pypirc` | None | Setup PyPI configuration file |
84
+ | `make check-pypirc` | None | Check PyPI configuration |
85
+ | `make clean` | None | Clean build artifacts |
86
+ | `make test` | `pytest`, `pytest-cov` | Run tests |
87
+ | `make format` | `black` | Format code |
88
+ | `make lint` | `flake8`, `mypy` | Lint code |
89
+
90
+ ### Quick Setup for Development
91
+ ```bash
92
+ # Install development dependencies
93
+ pip install build twine wheel setuptools pytest pytest-cov flake8 black mypy
94
+
95
+ # Or install from the project's optional dependencies
96
+ pip install -e ".[dev]"
97
+ ```
98
+
99
+ ## Release Process
100
+
101
+ ### Quick Release
102
+ ```bash
103
+ # Setup PyPI configuration (first time only)
104
+ make setup-pypirc
105
+
106
+ # Release to TestPyPI
107
+ ./scripts/release/release.sh test
108
+
109
+ # Release to PyPI
110
+ ./scripts/release/release.sh prod
111
+ ```
112
+
113
+ ### Step-by-step Release
114
+ ```bash
115
+ # Clean, build, check, and upload
116
+ ./scripts/release/clean.sh
117
+ ./scripts/release/build.sh
118
+ ./scripts/release/check.sh
119
+ ./scripts/release/upload_test.sh # or upload_prod.sh
120
+ ```
121
+
122
+ ## Installation
123
+
124
+ 1. Install OrcaGym (required):
125
+ ```bash
126
+ # Please follow the OrcaGym installation instructions
127
+ ```
128
+ 2. Clone this repository and install OrcaLab in editable mode:
129
+ ```bash
130
+ # required by pyside
131
+ sudo apt install libxcb-cursor0
132
+
133
+ git clone https://github.com/openverse-orca/OrcaLab.git
134
+ cd OrcaLab
135
+ pip install -e .
136
+ ```
137
+
138
+
139
+ ## Usage
140
+
141
+ To start OrcaLab, run:
142
+
143
+ ```bash
144
+ python run.py
145
+ ```
146
+
147
+
148
+ ## Notice
149
+
150
+ - Blocking function (like QDialog.exec()) should not be called in async function directly. It will stop the async loop in a strange way. There are two ways to work around:
151
+ - wrap in `qasync.asyncWrap`
152
+ - invoke by a qt signal.
153
+
154
+ ``` python
155
+ # wrap in `qasync.asyncWrap`
156
+
157
+ async def foo():
158
+ def bloc_task():
159
+ return dialog.exec()
160
+
161
+ await asyncWrap(bloc_task)
162
+
163
+ # invoke by a qt signal
164
+
165
+ def bloc_task():
166
+ return dialog.exec()
167
+
168
+ some_signal.connect(bloc_task)
169
+
170
+ ```
171
+
172
+ ## 常见问题
173
+
174
+ ### Linux上出现 version `GLIBCXX_3.4.30' not found
175
+ conda update -c conda-forge libstdcxx-ng
176
+
177
+
178
+
179
+ ## License
180
+
181
+ This project is licensed under the terms of the [LICENSE](LICENSE) file.
@@ -0,0 +1,72 @@
1
+ orca_lab-25.9.0.dist-info/licenses/LICENSE,sha256=IAibJRQUWEGQheOOblT8gFgk22tipq6IcpFXADQGCP4,1095
2
+ orcalab/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ orcalab/actor.py,sha256=dUUyiVgweVtN1gXYi4ZuE2p-sOP3gluGOKAzkMXexxk,4347
4
+ orcalab/application_bus.py,sha256=Rm3xTI2u2bY4gMiDgj80DEZdQY1cv8YbfdOrw4t_4z4,349
5
+ orcalab/asset_service.py,sha256=njGQxHot9sj14AZlTQ9xjFGTM6Rq3_mBfM7OUeseffU,1653
6
+ orcalab/asset_service_bus.py,sha256=-dJuTuFg9eFfxkdtTxmEGiheC83d4BMLLFZjon_WYXk,488
7
+ orcalab/asset_sync_service.py,sha256=abmGbXi0KsLm2pwNECDZZxzfAD0vNwKYSYXo9P5pPb8,14141
8
+ orcalab/asset_sync_ui.py,sha256=-MF5v81oDnM31tbIf4IEX5K7fUqB9r_eMRs_zSlkk9g,7149
9
+ orcalab/auth_service.py,sha256=MD-x6wmaaw-2ZM_lIAFXu12BSALPcQqBjYe3XDs06sg,8002
10
+ orcalab/config_service.py,sha256=JZC7OJTti6gEkof-mjiK8Eaqfi5-Qv8jEAj4WEHVcwM,5570
11
+ orcalab/event_bus.py,sha256=-5JAY3Pt6Rsnw4hNN4TYhilXKE6e0YDj2LzvGmnxXWc,3453
12
+ orcalab/local_scene.py,sha256=SU6YkTmc7G97qL2Yu61wri-lEy0GJUZ5Lk8ICRLQ59w,7425
13
+ orcalab/math.py,sha256=MUcHwXaK8yQvsgtJuUkFbUuoycpq_Js5uM-5zwYw9sk,10607
14
+ orcalab/path.py,sha256=NLA0CxS5uVVQOdtXrBJSfxufPYzDexjBbJ_y_O-tCII,2499
15
+ orcalab/project_util.py,sha256=_LjYWIctTjx9K_cmku68_XOqLK8bC2SE4PkrMYpFygs,4946
16
+ orcalab/pyside_util.py,sha256=O1WVAmKZWaeuOXeZerJIHLXqW1afBt3F-Q_AWPNBwpg,872
17
+ orcalab/remote_scene.py,sha256=2cVgwSdeQbbzLt688tjzuPIdUvOJudje0maiR5ID350,25418
18
+ orcalab/scene_edit_bus.py,sha256=DK6tN7spaQdDPcYcwQcHKVRSKncJDHb4fSt8kEQ72JA,5183
19
+ orcalab/scene_edit_service.py,sha256=nOrRNqTs7UMplFarjU2IwQ-ER3biFCj-McjKL4pUzTs,7544
20
+ orcalab/sim_process.py,sha256=m3HsJEnHlqGMED0twe88LFkeqWCcKZc81JFx8Mf-Wq0,533
21
+ orcalab/token_storage.py,sha256=LAIyGXf2wfzMsSotaad-EAUykzH2k0xcnXM3W089RoA,2868
22
+ orcalab/assets/assets.qrc,sha256=W1ZSv-Id2d3bayr-hUlpWdP5_mMIwG_DjfBXu5KY544,591
23
+ orcalab/assets/gen.py,sha256=zb2GxCzIXDdEGNLfBOKM9wucdo9HNhYGm0eDryfAqNg,234
24
+ orcalab/assets/rc_assets.py,sha256=Dr33d4V3UJBtzNri7lLowoItczRgpEN3YkqknYDUhyM,6120
25
+ orcalab/assets/icons/ic_fluent_add_20_filled.svg,sha256=2XD9hGlOYjONyj85jLLvdasl7CIJ-hGUXBWObgKnJ6c,454
26
+ orcalab/assets/icons/ic_fluent_eye_20_regular.svg,sha256=P-2yEb29XUfJ0eKoIP5z_9AGfr9VXtj-Q1AzoJ0NLR0,730
27
+ orcalab/assets/icons/ic_fluent_eye_off_20_regular.svg,sha256=gZsYAz7O3B-d7IMLqBGSXOUnaTjH11SkmJzdYx8G2H0,1183
28
+ orcalab/assets/icons/ic_fluent_filter_20_filled.svg,sha256=fEbpnY-joccvO70waqMWe8UOmuSPP5fFWbKJJLvukps,570
29
+ orcalab/assets/icons/ic_fluent_lock_closed_20_regular.svg,sha256=YrCk_Eym-U9C13EAGzgb3AujYCgQU5AWGWJSXrGbOiI,606
30
+ orcalab/assets/icons/ic_fluent_lock_open_20_regular.svg,sha256=NmQP-udujk7-5DghXAuwmI-tyO6Yu_1HSS8LdI9uH8g,660
31
+ orcalab/assets/icons/ic_fluent_pause_20_filled.svg,sha256=JIScWws61Angezb23XZWGeJbmuGJ76RpR3yU5KOpu6I,370
32
+ orcalab/assets/icons/ic_fluent_play_20_filled_green.svg,sha256=w26YqTsHV7mGn-6Z9MDtWBTMnfxkMGnrTv0d3jngXXw,313
33
+ orcalab/assets/icons/ic_fluent_stop_20_filled_red.svg,sha256=wMppuX_umpq1NkWetuQqAQ5vTW9yjz2k4Fw-Rh2yLw0,268
34
+ orcalab/copilot/__init__.py,sha256=D7Vm5tkfex3RDoVtF9Hb8zUOdkjkBMkSKf7KCtG8bG8,255
35
+ orcalab/copilot/service.py,sha256=2tJhqQ-4eeEkYcXuqxC3UTgwP1kD6z8zRiPC1VB4voU,17710
36
+ orcalab/protos/__init__.py,sha256=BEWEkM6Hq2h2h_cY8T50uG5cQuAZkT2491c3BCTGneM,83
37
+ orcalab/protos/edit_service.proto,sha256=RXHwR8NAIEtkAadlMSL0hd4Ht0w6UfaMy2WBChexsYI,6660
38
+ orcalab/protos/edit_service_pb2.py,sha256=Kna69jEUytZNmxaD5ExdENo9qvUz6U77YIrDtmP6Ljg,15791
39
+ orcalab/protos/edit_service_pb2_grpc.py,sha256=_4dHzhO7WIH2N6y-O42arCBG8PJPFoedAyNm95PF3pM,42988
40
+ orcalab/protos/generate_proto.py,sha256=B439HHYO7jkidKmBZDET8SwfA8EGapsMlpSOsVHlASs,759
41
+ orcalab/protos/url_service.proto,sha256=XIGYjW64xjfq-n4tHr7Nu5hbYi4cUs5ASaxF4s4lMks,328
42
+ orcalab/protos/url_service_pb2.py,sha256=jGexEzzw1wKcKholMO3OLuI3fssJRqV8yOqPcMQXDRs,1916
43
+ orcalab/protos/url_service_pb2_grpc.py,sha256=lUQNDNqRiEygAjvNBz4ce6gau0Nt3EjfwlqDDo3d0CA,3473
44
+ orcalab/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
+ orcalab/ui/actor_editor.py,sha256=UsNhScxjGFhOwwGU7i-0Fw2yWIvGA1Q2xx5TNP9FBQo,5969
46
+ orcalab/ui/actor_outline.py,sha256=Jl62T3een6WJGEmjIkZOVQFo8yy32sGyiRZ-EcB8yBU,10859
47
+ orcalab/ui/actor_outline_model.py,sha256=9iJVIXZuWlMO0xFdJ9CTqe0kX1SfuMxtO-dVkwA_Hbc,11815
48
+ orcalab/ui/asset_browser.py,sha256=jE7Wnsc3dcBbCmhQteD1lGDgJkBLgIPhB3v1gOEsspI,8414
49
+ orcalab/ui/auth_window.py,sha256=CXJp0Q7nDvTytTPNKmxJlIJ6xi9TastLVidS1KZ1LOU,5959
50
+ orcalab/ui/copilot.py,sha256=8D_p76dm2LO5nLbBbc6BM-4uuzhnNzsv9fILbLe_fVY,25211
51
+ orcalab/ui/float_edit.py,sha256=3VU1afvcAQ3bzJh_BxKQR5EVMLGHUZ1AZbSd6OOPm08,4859
52
+ orcalab/ui/launch_dialog.py,sha256=9PGw2Yz9c5rv0sDcbYergT_F3ZC0Ga7F7RvKvW8F_aM,10164
53
+ orcalab/ui/main_window.py,sha256=0th-nAy8jsJgeQtrTCp4VtLMq37M6aKyIQclVEtfP5A,33791
54
+ orcalab/ui/rename_dialog.py,sha256=Sctwo4KKp3xP5bkwNVkuf4mjmUpPRmUKJFIO2XL4E4U,2348
55
+ orcalab/ui/sync_progress_window.py,sha256=dvmkLB_S1IA3lqqXr3DNbTvZkYQzzGXwhE_6wNFM48o,13985
56
+ orcalab/ui/terminal_widget.py,sha256=MtT_0gQQuInrsuyZY-Grs1Qa0u5WaYk24kfYgn_zdfA,10499
57
+ orcalab/ui/tool_bar.py,sha256=bM_fXUPC5BDJ3sekCiN_zzWANWwaP68bWbCy_6r1wA4,1323
58
+ orcalab/ui/transform_edit.py,sha256=lNiynsMXPCtJfVMrKNZbCgjBReQ3CLz-BRXQE2YGgwc,3610
59
+ orcalab/ui/viewport.py,sha256=W_rztkzoSka_4eVJFEPINoQjMfH6tCKw-7wx2y7NvNw,1952
60
+ orcalab/undo_service/command.py,sha256=RcfIaJE97s-e8C9ZnsZi9eGKyo2A1N-C4yLPaQ1d1q8,2323
61
+ orcalab/undo_service/undo_service.py,sha256=EeGnyGort_YputzwCAXsYflDUEUpuvdjPEPYR9fqoWE,6443
62
+ orcalab/undo_service/undo_service_bus.py,sha256=OS60-dGac3X4PIv-AlPjrzzZTxZIyzbvDxv-VCVTWaY,836
63
+ orcalab/url_service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
+ orcalab/url_service/url_handler.py,sha256=vTOHVl35PVQy4rj-rOVXVTXoDvh9k5qCJRLKwqdPAyg,1319
65
+ orcalab/url_service/url_service.py,sha256=qas4qvz6LYlrLTMDGXNo77r52n9X2pfwglTUlGjt-Qc,1705
66
+ orcalab/url_service/url_util.py,sha256=jXlFGPlzPAHfgAcEGC9BbifulB7TyajOYg1CNbhqpNw,1587
67
+ orcalab/url_service/url_util_linux.py,sha256=x5-STEZZPE9IlRNkz6T9g-o3KGItHB9li2H9_YE61GU,1664
68
+ orcalab/url_service/url_util_windows.py,sha256=FsG3hHlbIdbS7vlFaiwmkDOQLBhbKlkUe6k6kKliQU4,2137
69
+ orca_lab-25.9.0.dist-info/METADATA,sha256=4-wIZ5pke5kL264ZG-myvl4V93VbjoXj7KScf4P43Co,5050
70
+ orca_lab-25.9.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
71
+ orca_lab-25.9.0.dist-info/top_level.txt,sha256=drzov7E-eqRe5ydwax4hioudYNpxUzqkyHFPuF_3fZs,8
72
+ orca_lab-25.9.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Shanghai Songying Technology Co.,Ltd.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1 @@
1
+ orcalab
orcalab/__init__.py ADDED
File without changes
orcalab/actor.py ADDED
@@ -0,0 +1,146 @@
1
+ from typing import List, override
2
+
3
+ from orcalab.path import Path
4
+ from orcalab.math import Transform
5
+
6
+ import copy
7
+
8
+ type ParentActor = GroupActor | None
9
+
10
+
11
+ class BaseActor:
12
+ def __init__(self, name: str, parent: ParentActor):
13
+ self._name = ""
14
+ self._parent = None
15
+ self._transform = Transform()
16
+ self._world_transform = None
17
+ self.name = name
18
+ self.parent = parent
19
+
20
+ def __repr__(self):
21
+ return f"BaseActor(name={self._name})"
22
+
23
+ @property
24
+ def name(self):
25
+ return self._name
26
+
27
+ @name.setter
28
+ def name(self, value):
29
+ if not isinstance(value, str) or not Path.is_valid_name(value):
30
+ raise ValueError(f"Invalid name: {value}")
31
+ self._name = value
32
+
33
+ @property
34
+ def parent(self) -> ParentActor:
35
+ return self._parent
36
+
37
+ @parent.setter
38
+ def parent(self, parent_actor):
39
+ if parent_actor is not None and not isinstance(parent_actor, GroupActor):
40
+ raise TypeError("parent must be an instance of GroupActor or None.")
41
+
42
+ if parent_actor == self._parent:
43
+ return
44
+
45
+ if self._parent is not None:
46
+ self._parent._children.remove(self)
47
+
48
+ if parent_actor is not None:
49
+ parent_actor._children.append(self)
50
+
51
+ self._parent = parent_actor
52
+ self._world_transform = None # Invalidate world transform cache
53
+
54
+ @property
55
+ def transform(self):
56
+ return copy.deepcopy(self._transform)
57
+
58
+ @transform.setter
59
+ def transform(self, value):
60
+ if not isinstance(value, Transform):
61
+ raise TypeError("transform must be an instance of Transform.")
62
+ self._transform = copy.deepcopy(value)
63
+
64
+ self._world_transform = None # Invalidate world transform cache
65
+
66
+ @property
67
+ def world_transform(self) -> Transform:
68
+ if self._world_transform is not None:
69
+ return self._world_transform
70
+
71
+ if self.parent is None:
72
+ self._world_transform = self.transform
73
+ else:
74
+ self._world_transform = self.parent.world_transform * self.transform
75
+
76
+ return self._world_transform
77
+
78
+ @world_transform.setter
79
+ def world_transform(self, value: Transform):
80
+ if not isinstance(value, Transform):
81
+ raise TypeError("world_transform must be an instance of Transform.")
82
+
83
+ if self.parent is None:
84
+ self.transform = value
85
+ else:
86
+ self.transform = self.parent.world_transform.inverse() * value
87
+
88
+ self._world_transform = value
89
+
90
+
91
+ class GroupActor(BaseActor):
92
+ def __init__(self, name: str, parent: ParentActor = None):
93
+ self._children: List[BaseActor] = []
94
+ super().__init__(name, parent)
95
+
96
+ def __repr__(self):
97
+ return f"GroupActor(name={self.name}, children_count={len(self._children)})"
98
+
99
+ @property
100
+ def children(self):
101
+ return self._children.copy()
102
+
103
+ def insert_child(self, index: int, child: BaseActor):
104
+ if not isinstance(child, BaseActor):
105
+ raise TypeError("Child must be an instance of GroupActor or AssetActor.")
106
+
107
+ if child in self._children:
108
+ raise ValueError(f"{child.name} is already a child of {self.name}")
109
+
110
+ if child.parent is not None:
111
+ child.parent.remove_child(child)
112
+
113
+ if index < 0 or index > len(self._children):
114
+ self._children.append(child)
115
+ else:
116
+ self._children.insert(index, child)
117
+
118
+ child._parent = self
119
+
120
+ def add_child(self, child: BaseActor):
121
+ self.insert_child(-1, child)
122
+
123
+ def remove_child(self, child: BaseActor):
124
+ if child in self._children:
125
+ self._children.remove(child)
126
+ child._parent = None
127
+ # Don't raise error if child is not in the list - this can happen during cleanup
128
+
129
+
130
+ class AssetActor(BaseActor):
131
+ def __init__(self, name: str, asset_path: str, parent: GroupActor = None):
132
+ super().__init__(name, parent)
133
+ self._asset_path = asset_path
134
+
135
+ def __repr__(self):
136
+ return f"AssetActor(name={self.name})"
137
+
138
+ @property
139
+ def asset_path(self):
140
+ return self._asset_path
141
+
142
+ @asset_path.setter
143
+ def asset_path(self, value):
144
+ if not isinstance(value, str) or len(value) == 0:
145
+ raise ValueError("asset_path name must be non-empty string")
146
+ self._asset_path = value
@@ -0,0 +1,17 @@
1
+ from orcalab.event_bus import create_event_bus
2
+ from typing import List
3
+
4
+ class ApplicationRequest:
5
+
6
+ def get_cache_folder(self, output: List[str]) -> None:
7
+ pass
8
+
9
+
10
+ ApplicationRequestBus = create_event_bus(ApplicationRequest)
11
+
12
+
13
+ class ApplicationNotification:
14
+ pass
15
+
16
+
17
+ ApplicationNotificationBus = create_event_bus(ApplicationNotification)
@@ -0,0 +1,50 @@
1
+ from datetime import datetime
2
+ from orcalab.asset_service_bus import AssetServiceRequest, AssetServiceRequestBus, AssetServiceNotificationBus
3
+ from orcalab.application_bus import ApplicationRequestBus
4
+
5
+ import aiohttp
6
+ import aiofiles
7
+
8
+ from typing import override
9
+
10
+
11
+ class AssetService(AssetServiceRequest):
12
+
13
+ def __init__(self):
14
+ super().__init__()
15
+ AssetServiceRequestBus.connect(self)
16
+
17
+ def destroy(self):
18
+ AssetServiceRequestBus.disconnect(self)
19
+
20
+ @override
21
+ async def download_asset_to_file(self, url: str, file: str) -> None:
22
+ async with aiofiles.open(file, "wb") as f:
23
+ async with aiohttp.ClientSession() as session:
24
+ async with session.get(url) as response:
25
+ if response.status != 200:
26
+ raise Exception(
27
+ f"Failed to download asset. Status code: {response.status}"
28
+ )
29
+ data = await response.read()
30
+ await f.write(data)
31
+
32
+ @override
33
+ async def download_asset_to_cache(self, url: str) -> None:
34
+ cache_folder = []
35
+ ApplicationRequestBus().get_cache_folder(cache_folder)
36
+
37
+ if len(cache_folder) == 0:
38
+ raise Exception("Cache folder is not set.")
39
+
40
+ cache_folder: str = cache_folder[0]
41
+
42
+ # name file with time and date.
43
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
44
+ filename = f"asset_{timestamp}.pak"
45
+
46
+ file_path = cache_folder + "/" + filename
47
+
48
+ await self.download_asset_to_file(url, file_path)
49
+
50
+ await AssetServiceNotificationBus().on_asset_downloaded(file_path)
@@ -0,0 +1,22 @@
1
+ from orcalab.event_bus import create_event_bus
2
+
3
+
4
+ class AssetServiceRequest:
5
+
6
+ async def download_asset_to_file(self, url: str, file: str) -> None:
7
+ pass
8
+
9
+ async def download_asset_to_cache(self, url: str) -> None:
10
+ pass
11
+
12
+
13
+ AssetServiceRequestBus = create_event_bus(AssetServiceRequest)
14
+
15
+
16
+ class AssetServiceNotification:
17
+
18
+ async def on_asset_downloaded(self, file: str) -> None:
19
+ pass
20
+
21
+
22
+ AssetServiceNotificationBus = create_event_bus(AssetServiceNotification)