https://github.com/lihpc-computational-geometry/bot
BlOcking Toolkit, a Python project for generating quad and hex block structures
https://github.com/lihpc-computational-geometry/bot
Last synced: about 1 month ago
JSON representation
BlOcking Toolkit, a Python project for generating quad and hex block structures
- Host: GitHub
- URL: https://github.com/lihpc-computational-geometry/bot
- Owner: LIHPC-Computational-Geometry
- License: agpl-3.0
- Created: 2026-03-12T13:57:26.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-06-10T14:49:33.000Z (about 2 months ago)
- Last Synced: 2026-06-10T16:24:18.253Z (about 2 months ago)
- Language: Python
- Homepage:
- Size: 724 KB
- Stars: 5
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: contributing.md
- License: LICENSE
Awesome Lists containing this project
README
# BOT — BlOcking Toolkit

[](https://codecov.io/gh/franck-ledoux/bot)
[](https://github.com/astral-sh/ruff)
**BOT** is a Python research sandbox for developing and testing interactive quad and hex mesh blocking algorithms, with a focus on programmatic and potentially AI-driven workflows.
The project combines a [gmsh](https://gmsh.info/)-based CAD model with a real-time [Panda3D](https://www.panda3d.org/) 3D viewer, both accessible from an interactive IPython session.
---
## Table of Contents
- [Project overview](#project-overview)
- [Architecture](#architecture)
- [Usage](#usage)
- [Development guide](#development-guide)
- [Project structure](#project-structure)
- [Contributing](#contributing)
---
## Project overview
BOT provides a programmable environment where you can:
- Load CAD geometry (`.geo`, `.step`, …) via gmsh/OpenCASCADE.
- Query and mutate the geometry programmatically (add points, query adjacencies, …).
- Visualise the model live in a 3D viewer.
- Pick locations in the viewport and feed them back to the model.
The goal is to build robust, well-specified geometric operations that can later be driven by an AI agent.
---
## Architecture
```
IPython (main thread) Panda3D subprocess (main thread)
───────────────────── ────────────────────────────────
Model (gmsh / OCC) ViewerApp (ShowBase)
└─ _notify_observers() ──pipe──► pipe_reader thread → cmd_queue
└─ _process_commands task
└─ scene.rebuild()
Viewer._send('update', data)
└─ conn.send(...) ──pipe──► same path
Picking (future):
◄──pipe── conn.send(('pick', coords))
Viewer._event_thread
└─ on_pick(coords)
```
> **Why a subprocess?** On macOS, OpenGL must run on the main thread of the process that owns the window. Spawning Panda3D in a dedicated subprocess leaves IPython's main thread fully interactive. All data exchanged over the pipe is plain picklable dicts — no gmsh dependency on the viewer side.
---
## Usage
### Interactive session (IPython)
```python
import bot
# 1. Load geometry
model = bot.Model()
model.open("data/profil_1.geo")
# 2. Start the viewer (non-blocking — Panda3D runs in a subprocess)
viewer = bot.Viewer()
viewer.connect(model).run()
# 3. Query the model
print(model.get_point_tags()) # [1, 2, 3, 4, 5, 6]
print(model.get_curve_tags()) # [1, 2, 3, 4, 5]
# 4. Mutate — the viewer updates automatically
model.add_point([10.0, 5.0, 0.0])
# 5. React to picking events
viewer.on_pick = lambda coords: model.add_point(coords)
# 6. Standard view shortcuts (in the viewer window)
# c — re-centre on model
# x/y/z — align to right / front / top view
# Scroll — zoom
# Drag — rotate | Shift+Drag — pan
# 7. Clean shutdown
viewer.stop()
model.finalize()
```
### Render data format
The data dict exchanged between the model and the viewer is a plain Python dict:
```python
{
'points': [(x, y, z), ...], # discretised mesh nodes
'edges': [(idx_a, idx_b, curve_tag), ...],
'bounds': {
'min': [x, y, z], 'max': [x, y, z],
'center': [x, y, z], 'size': [dx, dy, dz],
},
}
```
---
## Development guide
We use [uv](https://docs.astral.sh/uv/) for all dependency and environment management.
### Prerequisites
- Python ≥ 3.14
- [uv](https://docs.astral.sh/uv/) — install with `curl -LsSf https://astral.sh/uv/install.sh | sh`
- On headless Linux: `sudo apt-get install libglu1-mesa libosmesa6`
### 1. Clone and set up
```bash
git clone --recurse-submodules https://github.com/franck-ledoux/bot.git
cd bot
uv sync # creates .venv and installs all production + dev dependencies
```
> **Never edit `uv.lock` by hand.** Always commit it — it guarantees every contributor uses the exact same dependency versions.
### 2. Add or remove dependencies
```bash
uv add # production dependency
uv add --dev # development-only dependency
uv remove
```
### 3. Run the test suite
```bash
uv run pytest # runs all tests + coverage (configured in pyproject.toml)
```
Coverage reports are written to:
- **Terminal** — summary after each run.
- **`htmlcov/index.html`** — full line-by-line HTML report.
To run a specific subset:
```bash
uv run pytest tests/unit/ # unit tests only (no display required)
uv run pytest tests/system/ # system tests (subprocess tests open a window)
uv run pytest -k "TestAddPoint" # filter by name
```
### 4. Generate the documentation
Live preview (auto-refreshes on save):
```bash
uv run pdoc ./bot
```
Build static HTML into `docs/`:
```bash
uv run pdoc ./bot -o ./docs
```
### 5. Continuous integration
Each push and pull request automatically triggers a GitHub Actions workflow that:
- Runs the full test suite on Ubuntu.
- Uploads coverage to [Codecov](https://codecov.io/gh/franck-ledoux/bot).
---
## Project structure
```
bot/
├── bot/
│ ├── core/
│ │ └── cad.py # Model — gmsh/OCC geometry + observer pattern
│ ├── view/
│ │ ├── scene.py # Scene + Gizmo — Panda3D geometry rendering
│ │ └── utils.py # View-layer utilities (ColorGenerator, …)
│ ├── control/
│ │ ├── camera.py # CameraController — orthographic camera
│ │ ├── keyboard.py # KeyboardHandler
│ │ └── mouse.py # MouseHandler
│ └── viewer/
│ ├── viewer.py # Viewer — public API, manages the subprocess
│ └── app.py # ViewerApp — Panda3D ShowBase (runs in subprocess)
|── ferrispline/ # Submodule library for generating, manipulating and computing hexahedral meshes
├── tests/
│ ├── unit/ # Isolated class tests (no display required)
│ └── system/ # End-to-end workflow tests
├── data/ # Sample .geo files
├── docs/ # Generated HTML documentation
├── bot_config.toml # Runtime configuration (scene, camera)
├── pyproject.toml # Project metadata, dependencies, pytest config
└── uv.lock # Deterministic lockfile — always commit this
```
---
## Contributing
We follow a **branch-and-pull-request** workflow. Direct pushes to `main` are not allowed.
### Branch naming
| Type | Pattern | Example |
|---|---|---|
| New feature | `feature/` | `feature/picking-support` |
| Bug fix | `fix/` | `fix/camera-clip-plane` |
| Documentation | `docs/` | `docs/update-readme` |
| Refactoring | `refactor/` | `refactor/scene-rename` |
| Tests | `test/` | `test/add-system-viewer` |
### Workflow
```bash
# 1. Branch off main (always keep main up to date first)
git checkout main && git pull
git checkout -b feature/my-feature
# 2. Develop, commit often
git add
git commit -m "feat: add picking event callback"
# 3. Keep your branch up to date
git fetch origin && git rebase origin/main
# 4. Push and open a pull request
git push -u origin feature/my-feature
# → open a PR on GitHub targeting main
```
### Commit message conventions
We follow [Conventional Commits](https://www.conventionalcommits.org/):
```
:
Types: feat | fix | docs | refactor | test | chore | perf
```
Examples:
```
feat: add on_pick callback to Viewer
fix: prevent camera clipping on small models
test: add system tests for viewer subprocess lifecycle
docs: document Scene and Gizmo classes
```
### Pull request checklist
Before requesting a review, make sure:
- [ ] All existing tests pass: `uv run pytest`
- [ ] New code is covered by unit or system tests.
- [ ] Docstrings are present on all new public classes and methods (English, Google style).
- [ ] `uv.lock` is committed if dependencies changed.
- [ ] The PR description explains **what** changed and **why**.
- [ ] The branch is rebased on the latest `main`.
### Code standards
- **Formatting:** standard Python conventions (PEP 8).
- **Docstrings:** English, Google style, on all public symbols.
- **Type hints:** use them on all new function signatures.
- **No direct push to `main`** — all changes go through a PR.
### Troubleshooting
**Panda3D / OpenGL errors on headless Linux:**
```bash
sudo apt-get install libglu1-mesa libosmesa6
```
**Subprocess tests open a window — is that expected?**
Yes. `tests/system/test_viewer_subprocess.py` starts the real Panda3D process. Those tests are automatically skipped in headless environments (`DISPLAY` / `WAYLAND_DISPLAY` not set).