orca-lab 25.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- orca_lab-25.9.0/LICENSE +22 -0
- orca_lab-25.9.0/MANIFEST.in +38 -0
- orca_lab-25.9.0/PKG-INFO +181 -0
- orca_lab-25.9.0/README.md +141 -0
- orca_lab-25.9.0/orca_lab.egg-info/SOURCES.txt +71 -0
- orca_lab-25.9.0/orcalab/__init__.py +0 -0
- orca_lab-25.9.0/orcalab/actor.py +146 -0
- orca_lab-25.9.0/orcalab/application_bus.py +17 -0
- orca_lab-25.9.0/orcalab/asset_service.py +50 -0
- orca_lab-25.9.0/orcalab/asset_service_bus.py +22 -0
- orca_lab-25.9.0/orcalab/asset_sync_service.py +389 -0
- orca_lab-25.9.0/orcalab/asset_sync_ui.py +212 -0
- orca_lab-25.9.0/orcalab/assets/assets.qrc +11 -0
- orca_lab-25.9.0/orcalab/assets/gen.py +7 -0
- orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_add_20_filled.svg +3 -0
- orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_eye_20_regular.svg +3 -0
- orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_eye_off_20_regular.svg +3 -0
- orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_filter_20_filled.svg +3 -0
- orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_lock_closed_20_regular.svg +3 -0
- orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_lock_open_20_regular.svg +3 -0
- orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_pause_20_filled.svg +3 -0
- orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_play_20_filled_green.svg +3 -0
- orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_stop_20_filled_red.svg +3 -0
- orca_lab-25.9.0/orcalab/assets/rc_assets.py +302 -0
- orca_lab-25.9.0/orcalab/auth_service.py +242 -0
- orca_lab-25.9.0/orcalab/config_service.py +163 -0
- orca_lab-25.9.0/orcalab/copilot/__init__.py +10 -0
- orca_lab-25.9.0/orcalab/copilot/service.py +456 -0
- orca_lab-25.9.0/orcalab/event_bus.py +105 -0
- orca_lab-25.9.0/orcalab/local_scene.py +223 -0
- orca_lab-25.9.0/orcalab/math.py +334 -0
- orca_lab-25.9.0/orcalab/path.py +101 -0
- orca_lab-25.9.0/orcalab/project_util.py +152 -0
- orca_lab-25.9.0/orcalab/protos/__init__.py +3 -0
- orca_lab-25.9.0/orcalab/protos/edit_service.proto +265 -0
- orca_lab-25.9.0/orcalab/protos/edit_service_pb2.py +134 -0
- orca_lab-25.9.0/orcalab/protos/edit_service_pb2_grpc.py +1043 -0
- orca_lab-25.9.0/orcalab/protos/generate_proto.py +32 -0
- orca_lab-25.9.0/orcalab/protos/url_service.proto +21 -0
- orca_lab-25.9.0/orcalab/protos/url_service_pb2.py +42 -0
- orca_lab-25.9.0/orcalab/protos/url_service_pb2_grpc.py +97 -0
- orca_lab-25.9.0/orcalab/pyside_util.py +27 -0
- orca_lab-25.9.0/orcalab/remote_scene.py +688 -0
- orca_lab-25.9.0/orcalab/scene_edit_bus.py +219 -0
- orca_lab-25.9.0/orcalab/scene_edit_service.py +246 -0
- orca_lab-25.9.0/orcalab/sim_process.py +28 -0
- orca_lab-25.9.0/orcalab/token_storage.py +107 -0
- orca_lab-25.9.0/orcalab/ui/__init__.py +0 -0
- orca_lab-25.9.0/orcalab/ui/actor_editor.py +200 -0
- orca_lab-25.9.0/orcalab/ui/actor_outline.py +320 -0
- orca_lab-25.9.0/orcalab/ui/actor_outline_model.py +394 -0
- orca_lab-25.9.0/orcalab/ui/asset_browser.py +245 -0
- orca_lab-25.9.0/orcalab/ui/auth_window.py +191 -0
- orca_lab-25.9.0/orcalab/ui/copilot.py +580 -0
- orca_lab-25.9.0/orcalab/ui/float_edit.py +141 -0
- orca_lab-25.9.0/orcalab/ui/launch_dialog.py +280 -0
- orca_lab-25.9.0/orcalab/ui/main_window.py +883 -0
- orca_lab-25.9.0/orcalab/ui/rename_dialog.py +84 -0
- orca_lab-25.9.0/orcalab/ui/sync_progress_window.py +358 -0
- orca_lab-25.9.0/orcalab/ui/terminal_widget.py +308 -0
- orca_lab-25.9.0/orcalab/ui/tool_bar.py +43 -0
- orca_lab-25.9.0/orcalab/ui/transform_edit.py +131 -0
- orca_lab-25.9.0/orcalab/ui/viewport.py +64 -0
- orca_lab-25.9.0/orcalab/undo_service/command.py +90 -0
- orca_lab-25.9.0/orcalab/undo_service/undo_service.py +171 -0
- orca_lab-25.9.0/orcalab/undo_service/undo_service_bus.py +48 -0
- orca_lab-25.9.0/orcalab/url_service/__init__.py +0 -0
- orca_lab-25.9.0/orcalab/url_service/url_handler.py +57 -0
- orca_lab-25.9.0/orcalab/url_service/url_service.py +51 -0
- orca_lab-25.9.0/orcalab/url_service/url_util.py +58 -0
- orca_lab-25.9.0/orcalab/url_service/url_util_linux.py +74 -0
- orca_lab-25.9.0/orcalab/url_service/url_util_windows.py +67 -0
- orca_lab-25.9.0/pyproject.toml +62 -0
- orca_lab-25.9.0/setup.cfg +4 -0
orca_lab-25.9.0/LICENSE
ADDED
|
@@ -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,38 @@
|
|
|
1
|
+
# Include package data files
|
|
2
|
+
include README.md
|
|
3
|
+
include LICENSE
|
|
4
|
+
include pyproject.toml
|
|
5
|
+
|
|
6
|
+
# Include proto files
|
|
7
|
+
recursive-include orcalab/protos *.proto
|
|
8
|
+
|
|
9
|
+
# Include asset files
|
|
10
|
+
recursive-include orcalab/assets *.qrc
|
|
11
|
+
recursive-include orcalab/assets *.svg
|
|
12
|
+
recursive-include orcalab/assets *.png
|
|
13
|
+
recursive-include orcalab/assets *.jpg
|
|
14
|
+
recursive-include orcalab/assets *.jpeg
|
|
15
|
+
|
|
16
|
+
# Include configuration files
|
|
17
|
+
recursive-include orcalab *.toml
|
|
18
|
+
recursive-include orcalab *.yaml
|
|
19
|
+
recursive-include orcalab *.yml
|
|
20
|
+
|
|
21
|
+
# Include type hints
|
|
22
|
+
recursive-include orcalab *.pyi
|
|
23
|
+
|
|
24
|
+
# Exclude test files
|
|
25
|
+
recursive-exclude test *
|
|
26
|
+
recursive-exclude tests *
|
|
27
|
+
recursive-exclude examples *
|
|
28
|
+
recursive-exclude doc *
|
|
29
|
+
recursive-exclude docs *
|
|
30
|
+
|
|
31
|
+
# Exclude build artifacts
|
|
32
|
+
exclude Makefile
|
|
33
|
+
recursive-exclude scripts *
|
|
34
|
+
recursive-exclude .git *
|
|
35
|
+
recursive-exclude __pycache__ *
|
|
36
|
+
recursive-exclude *.pyc
|
|
37
|
+
recursive-exclude *.pyo
|
|
38
|
+
recursive-exclude *.egg-info *
|
orca_lab-25.9.0/PKG-INFO
ADDED
|
@@ -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,141 @@
|
|
|
1
|
+
# OrcaLab
|
|
2
|
+
|
|
3
|
+
OrcaLab is a front-end of OrcaGym. It provides a user-interface for scene assembling and simulation.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- TODO
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
- Python 3.12 or higher
|
|
12
|
+
- [OrcaGym](https://github.com/your-org/OrcaGym) (required dependency)
|
|
13
|
+
- Other dependencies listed in `pyproject.toml`
|
|
14
|
+
|
|
15
|
+
## Development Requirements
|
|
16
|
+
|
|
17
|
+
For building and releasing packages, the following pip packages are required:
|
|
18
|
+
|
|
19
|
+
### Core Build Tools
|
|
20
|
+
```bash
|
|
21
|
+
pip install build twine wheel setuptools
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Development Tools (Optional)
|
|
25
|
+
```bash
|
|
26
|
+
pip install pytest pytest-cov flake8 black mypy
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Make Commands and Required Packages
|
|
30
|
+
|
|
31
|
+
The project includes a `Makefile` with various commands. Here are the required packages for each command:
|
|
32
|
+
|
|
33
|
+
| Make Command | Required pip packages | Description |
|
|
34
|
+
|-------------|----------------------|-------------|
|
|
35
|
+
| `make build` | `build`, `setuptools`, `wheel` | Build distribution packages |
|
|
36
|
+
| `make check` | `twine` | Check package quality |
|
|
37
|
+
| `make test-install` | `build`, `setuptools`, `wheel` | Test local installation |
|
|
38
|
+
| `make test-install-testpypi` | `build`, `setuptools`, `wheel` | Test TestPyPI installation |
|
|
39
|
+
| `make test-install-pypi` | `build`, `setuptools`, `wheel` | Test PyPI installation |
|
|
40
|
+
| `make release-test` | `build`, `twine`, `setuptools`, `wheel` | Release to TestPyPI |
|
|
41
|
+
| `make release-prod` | `build`, `twine`, `setuptools`, `wheel` | Release to PyPI |
|
|
42
|
+
| `make bump-version` | None (uses sed) | Bump version number |
|
|
43
|
+
| `make setup-pypirc` | None | Setup PyPI configuration file |
|
|
44
|
+
| `make check-pypirc` | None | Check PyPI configuration |
|
|
45
|
+
| `make clean` | None | Clean build artifacts |
|
|
46
|
+
| `make test` | `pytest`, `pytest-cov` | Run tests |
|
|
47
|
+
| `make format` | `black` | Format code |
|
|
48
|
+
| `make lint` | `flake8`, `mypy` | Lint code |
|
|
49
|
+
|
|
50
|
+
### Quick Setup for Development
|
|
51
|
+
```bash
|
|
52
|
+
# Install development dependencies
|
|
53
|
+
pip install build twine wheel setuptools pytest pytest-cov flake8 black mypy
|
|
54
|
+
|
|
55
|
+
# Or install from the project's optional dependencies
|
|
56
|
+
pip install -e ".[dev]"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Release Process
|
|
60
|
+
|
|
61
|
+
### Quick Release
|
|
62
|
+
```bash
|
|
63
|
+
# Setup PyPI configuration (first time only)
|
|
64
|
+
make setup-pypirc
|
|
65
|
+
|
|
66
|
+
# Release to TestPyPI
|
|
67
|
+
./scripts/release/release.sh test
|
|
68
|
+
|
|
69
|
+
# Release to PyPI
|
|
70
|
+
./scripts/release/release.sh prod
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Step-by-step Release
|
|
74
|
+
```bash
|
|
75
|
+
# Clean, build, check, and upload
|
|
76
|
+
./scripts/release/clean.sh
|
|
77
|
+
./scripts/release/build.sh
|
|
78
|
+
./scripts/release/check.sh
|
|
79
|
+
./scripts/release/upload_test.sh # or upload_prod.sh
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Installation
|
|
83
|
+
|
|
84
|
+
1. Install OrcaGym (required):
|
|
85
|
+
```bash
|
|
86
|
+
# Please follow the OrcaGym installation instructions
|
|
87
|
+
```
|
|
88
|
+
2. Clone this repository and install OrcaLab in editable mode:
|
|
89
|
+
```bash
|
|
90
|
+
# required by pyside
|
|
91
|
+
sudo apt install libxcb-cursor0
|
|
92
|
+
|
|
93
|
+
git clone https://github.com/openverse-orca/OrcaLab.git
|
|
94
|
+
cd OrcaLab
|
|
95
|
+
pip install -e .
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
## Usage
|
|
100
|
+
|
|
101
|
+
To start OrcaLab, run:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
python run.py
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
## Notice
|
|
109
|
+
|
|
110
|
+
- 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:
|
|
111
|
+
- wrap in `qasync.asyncWrap`
|
|
112
|
+
- invoke by a qt signal.
|
|
113
|
+
|
|
114
|
+
``` python
|
|
115
|
+
# wrap in `qasync.asyncWrap`
|
|
116
|
+
|
|
117
|
+
async def foo():
|
|
118
|
+
def bloc_task():
|
|
119
|
+
return dialog.exec()
|
|
120
|
+
|
|
121
|
+
await asyncWrap(bloc_task)
|
|
122
|
+
|
|
123
|
+
# invoke by a qt signal
|
|
124
|
+
|
|
125
|
+
def bloc_task():
|
|
126
|
+
return dialog.exec()
|
|
127
|
+
|
|
128
|
+
some_signal.connect(bloc_task)
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 常见问题
|
|
133
|
+
|
|
134
|
+
### Linux上出现 version `GLIBCXX_3.4.30' not found
|
|
135
|
+
conda update -c conda-forge libstdcxx-ng
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
This project is licensed under the terms of the [LICENSE](LICENSE) file.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
orcalab/__init__.py
|
|
6
|
+
orcalab/actor.py
|
|
7
|
+
orcalab/application_bus.py
|
|
8
|
+
orcalab/asset_service.py
|
|
9
|
+
orcalab/asset_service_bus.py
|
|
10
|
+
orcalab/asset_sync_service.py
|
|
11
|
+
orcalab/asset_sync_ui.py
|
|
12
|
+
orcalab/auth_service.py
|
|
13
|
+
orcalab/config_service.py
|
|
14
|
+
orcalab/event_bus.py
|
|
15
|
+
orcalab/local_scene.py
|
|
16
|
+
orcalab/math.py
|
|
17
|
+
orcalab/path.py
|
|
18
|
+
orcalab/project_util.py
|
|
19
|
+
orcalab/pyside_util.py
|
|
20
|
+
orcalab/remote_scene.py
|
|
21
|
+
orcalab/scene_edit_bus.py
|
|
22
|
+
orcalab/scene_edit_service.py
|
|
23
|
+
orcalab/sim_process.py
|
|
24
|
+
orcalab/token_storage.py
|
|
25
|
+
orcalab/assets/assets.qrc
|
|
26
|
+
orcalab/assets/gen.py
|
|
27
|
+
orcalab/assets/rc_assets.py
|
|
28
|
+
orcalab/assets/icons/ic_fluent_add_20_filled.svg
|
|
29
|
+
orcalab/assets/icons/ic_fluent_eye_20_regular.svg
|
|
30
|
+
orcalab/assets/icons/ic_fluent_eye_off_20_regular.svg
|
|
31
|
+
orcalab/assets/icons/ic_fluent_filter_20_filled.svg
|
|
32
|
+
orcalab/assets/icons/ic_fluent_lock_closed_20_regular.svg
|
|
33
|
+
orcalab/assets/icons/ic_fluent_lock_open_20_regular.svg
|
|
34
|
+
orcalab/assets/icons/ic_fluent_pause_20_filled.svg
|
|
35
|
+
orcalab/assets/icons/ic_fluent_play_20_filled_green.svg
|
|
36
|
+
orcalab/assets/icons/ic_fluent_stop_20_filled_red.svg
|
|
37
|
+
orcalab/copilot/__init__.py
|
|
38
|
+
orcalab/copilot/service.py
|
|
39
|
+
orcalab/protos/__init__.py
|
|
40
|
+
orcalab/protos/edit_service.proto
|
|
41
|
+
orcalab/protos/edit_service_pb2.py
|
|
42
|
+
orcalab/protos/edit_service_pb2_grpc.py
|
|
43
|
+
orcalab/protos/generate_proto.py
|
|
44
|
+
orcalab/protos/url_service.proto
|
|
45
|
+
orcalab/protos/url_service_pb2.py
|
|
46
|
+
orcalab/protos/url_service_pb2_grpc.py
|
|
47
|
+
orcalab/ui/__init__.py
|
|
48
|
+
orcalab/ui/actor_editor.py
|
|
49
|
+
orcalab/ui/actor_outline.py
|
|
50
|
+
orcalab/ui/actor_outline_model.py
|
|
51
|
+
orcalab/ui/asset_browser.py
|
|
52
|
+
orcalab/ui/auth_window.py
|
|
53
|
+
orcalab/ui/copilot.py
|
|
54
|
+
orcalab/ui/float_edit.py
|
|
55
|
+
orcalab/ui/launch_dialog.py
|
|
56
|
+
orcalab/ui/main_window.py
|
|
57
|
+
orcalab/ui/rename_dialog.py
|
|
58
|
+
orcalab/ui/sync_progress_window.py
|
|
59
|
+
orcalab/ui/terminal_widget.py
|
|
60
|
+
orcalab/ui/tool_bar.py
|
|
61
|
+
orcalab/ui/transform_edit.py
|
|
62
|
+
orcalab/ui/viewport.py
|
|
63
|
+
orcalab/undo_service/command.py
|
|
64
|
+
orcalab/undo_service/undo_service.py
|
|
65
|
+
orcalab/undo_service/undo_service_bus.py
|
|
66
|
+
orcalab/url_service/__init__.py
|
|
67
|
+
orcalab/url_service/url_handler.py
|
|
68
|
+
orcalab/url_service/url_service.py
|
|
69
|
+
orcalab/url_service/url_util.py
|
|
70
|
+
orcalab/url_service/url_util_linux.py
|
|
71
|
+
orcalab/url_service/url_util_windows.py
|
|
File without changes
|
|
@@ -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)
|