{"id":51014212,"url":"https://github.com/lihpc-computational-geometry/bot","last_synced_at":"2026-06-21T08:01:36.082Z","repository":{"id":353138082,"uuid":"1179904930","full_name":"LIHPC-Computational-Geometry/bot","owner":"LIHPC-Computational-Geometry","description":"BlOcking Toolkit, a Python project for generating quad and hex block structures","archived":false,"fork":false,"pushed_at":"2026-06-10T14:49:33.000Z","size":741,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-10T16:24:18.253Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LIHPC-Computational-Geometry.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"contributing.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-12T13:57:26.000Z","updated_at":"2026-06-07T17:28:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/LIHPC-Computational-Geometry/bot","commit_stats":null,"previous_names":["lihpc-computational-geometry/bot"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/LIHPC-Computational-Geometry/bot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LIHPC-Computational-Geometry%2Fbot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LIHPC-Computational-Geometry%2Fbot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LIHPC-Computational-Geometry%2Fbot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LIHPC-Computational-Geometry%2Fbot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LIHPC-Computational-Geometry","download_url":"https://codeload.github.com/LIHPC-Computational-Geometry/bot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LIHPC-Computational-Geometry%2Fbot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34601662,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-21T02:00:05.568Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-21T08:01:34.147Z","updated_at":"2026-06-21T08:01:36.049Z","avatar_url":"https://github.com/LIHPC-Computational-Geometry.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BOT — BlOcking Toolkit\n\n![Tests](https://github.com/franck-ledoux/bot/actions/workflows/tests.yml/badge.svg)\n[![codecov](https://codecov.io/gh/franck-ledoux/bot/graph/badge.svg?token=HGY9PK4OA4)](https://codecov.io/gh/franck-ledoux/bot)\n[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)\n\n**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.\n\nThe 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.\n\n---\n\n## Table of Contents\n\n- [Project overview](#project-overview)\n- [Architecture](#architecture)\n- [Usage](#usage)\n- [Development guide](#development-guide)\n- [Project structure](#project-structure)\n- [Contributing](#contributing)\n\n---\n\n## Project overview\n\nBOT provides a programmable environment where you can:\n\n- Load CAD geometry (`.geo`, `.step`, …) via gmsh/OpenCASCADE.\n- Query and mutate the geometry programmatically (add points, query adjacencies, …).\n- Visualise the model live in a 3D viewer.\n- Pick locations in the viewport and feed them back to the model.\n\nThe goal is to build robust, well-specified geometric operations that can later be driven by an AI agent.\n\n---\n\n## Architecture\n\n```\nIPython (main thread)                 Panda3D subprocess (main thread)\n─────────────────────                 ────────────────────────────────\nModel (gmsh / OCC)                    ViewerApp (ShowBase)\n  └─ _notify_observers()  ──pipe──►   pipe_reader thread → cmd_queue\n                                        └─ _process_commands task\n                                             └─ scene.rebuild()\nViewer._send('update', data)\n  └─ conn.send(...)        ──pipe──►   same path\n\nPicking (future):\n                             ◄──pipe── conn.send(('pick', coords))\nViewer._event_thread\n  └─ on_pick(coords)\n```\n\n\u003e **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.\n\n---\n\n## Usage\n\n### Interactive session (IPython)\n\n```python\nimport bot\n\n# 1. Load geometry\nmodel = bot.Model()\nmodel.open(\"data/profil_1.geo\")\n\n# 2. Start the viewer (non-blocking — Panda3D runs in a subprocess)\nviewer = bot.Viewer()\nviewer.connect(model).run()\n\n# 3. Query the model\nprint(model.get_point_tags())   # [1, 2, 3, 4, 5, 6]\nprint(model.get_curve_tags())   # [1, 2, 3, 4, 5]\n\n# 4. Mutate — the viewer updates automatically\nmodel.add_point([10.0, 5.0, 0.0])\n\n# 5. React to picking events\nviewer.on_pick = lambda coords: model.add_point(coords)\n\n# 6. Standard view shortcuts (in the viewer window)\n#    c       — re-centre on model\n#    x/y/z   — align to right / front / top view\n#    Scroll  — zoom\n#    Drag    — rotate   |   Shift+Drag — pan\n\n# 7. Clean shutdown\nviewer.stop()\nmodel.finalize()\n```\n\n### Render data format\n\nThe data dict exchanged between the model and the viewer is a plain Python dict:\n\n```python\n{\n    'points': [(x, y, z), ...],               # discretised mesh nodes\n    'edges':  [(idx_a, idx_b, curve_tag), ...],\n    'bounds': {\n        'min': [x, y, z], 'max': [x, y, z],\n        'center': [x, y, z], 'size': [dx, dy, dz],\n    },\n}\n```\n\n---\n\n## Development guide\n\nWe use [uv](https://docs.astral.sh/uv/) for all dependency and environment management.\n\n### Prerequisites\n\n- Python ≥ 3.14\n- [uv](https://docs.astral.sh/uv/) — install with `curl -LsSf https://astral.sh/uv/install.sh | sh`\n- On headless Linux: `sudo apt-get install libglu1-mesa libosmesa6`\n\n### 1. Clone and set up\n\n```bash\ngit clone --recurse-submodules https://github.com/franck-ledoux/bot.git\ncd bot\nuv sync          # creates .venv and installs all production + dev dependencies\n```\n\n\u003e **Never edit `uv.lock` by hand.** Always commit it — it guarantees every contributor uses the exact same dependency versions.\n\n### 2. Add or remove dependencies\n\n```bash\nuv add \u003cpackage\u003e            # production dependency\nuv add --dev \u003cpackage\u003e      # development-only dependency\nuv remove \u003cpackage\u003e\n```\n\n### 3. Run the test suite\n\n```bash\nuv run pytest               # runs all tests + coverage (configured in pyproject.toml)\n```\n\nCoverage reports are written to:\n- **Terminal** — summary after each run.\n- **`htmlcov/index.html`** — full line-by-line HTML report.\n\nTo run a specific subset:\n\n```bash\nuv run pytest tests/unit/           # unit tests only (no display required)\nuv run pytest tests/system/         # system tests (subprocess tests open a window)\nuv run pytest -k \"TestAddPoint\"     # filter by name\n```\n\n### 4. Generate the documentation\n\nLive preview (auto-refreshes on save):\n```bash\nuv run pdoc ./bot\n```\n\nBuild static HTML into `docs/`:\n```bash\nuv run pdoc ./bot -o ./docs\n```\n\n### 5. Continuous integration\n\nEach push and pull request automatically triggers a GitHub Actions workflow that:\n\n- Runs the full test suite on Ubuntu.\n- Uploads coverage to [Codecov](https://codecov.io/gh/franck-ledoux/bot).\n\n---\n\n## Project structure\n\n```\nbot/\n├── bot/\n│   ├── core/\n│   │   └── cad.py          # Model — gmsh/OCC geometry + observer pattern\n│   ├── view/\n│   │   ├── scene.py         # Scene + Gizmo — Panda3D geometry rendering\n│   │   └── utils.py         # View-layer utilities (ColorGenerator, …)\n│   ├── control/\n│   │   ├── camera.py        # CameraController — orthographic camera\n│   │   ├── keyboard.py      # KeyboardHandler\n│   │   └── mouse.py         # MouseHandler\n│   └── viewer/\n│       ├── viewer.py        # Viewer — public API, manages the subprocess\n│       └── app.py           # ViewerApp — Panda3D ShowBase (runs in subprocess)\n|── ferrispline/             # Submodule library for generating, manipulating and computing hexahedral meshes\n├── tests/\n│   ├── unit/                # Isolated class tests (no display required)\n│   └── system/              # End-to-end workflow tests\n├── data/                    # Sample .geo files\n├── docs/                    # Generated HTML documentation\n├── bot_config.toml          # Runtime configuration (scene, camera)\n├── pyproject.toml           # Project metadata, dependencies, pytest config\n└── uv.lock                  # Deterministic lockfile — always commit this\n```\n\n---\n\n## Contributing\n\nWe follow a **branch-and-pull-request** workflow. Direct pushes to `main` are not allowed.\n\n### Branch naming\n\n| Type | Pattern | Example |\n|---|---|---|\n| New feature | `feature/\u003cshort-description\u003e` | `feature/picking-support` |\n| Bug fix | `fix/\u003cshort-description\u003e` | `fix/camera-clip-plane` |\n| Documentation | `docs/\u003cshort-description\u003e` | `docs/update-readme` |\n| Refactoring | `refactor/\u003cshort-description\u003e` | `refactor/scene-rename` |\n| Tests | `test/\u003cshort-description\u003e` | `test/add-system-viewer` |\n\n### Workflow\n\n```bash\n# 1. Branch off main (always keep main up to date first)\ngit checkout main \u0026\u0026 git pull\ngit checkout -b feature/my-feature\n\n# 2. Develop, commit often\ngit add \u003cfiles\u003e\ngit commit -m \"feat: add picking event callback\"\n\n# 3. Keep your branch up to date\ngit fetch origin \u0026\u0026 git rebase origin/main\n\n# 4. Push and open a pull request\ngit push -u origin feature/my-feature\n# → open a PR on GitHub targeting main\n```\n\n### Commit message conventions\n\nWe follow [Conventional Commits](https://www.conventionalcommits.org/):\n\n```\n\u003ctype\u003e: \u003cshort summary\u003e\n\nTypes: feat | fix | docs | refactor | test | chore | perf\n```\n\nExamples:\n```\nfeat: add on_pick callback to Viewer\nfix: prevent camera clipping on small models\ntest: add system tests for viewer subprocess lifecycle\ndocs: document Scene and Gizmo classes\n```\n\n### Pull request checklist\n\nBefore requesting a review, make sure:\n\n- [ ] All existing tests pass: `uv run pytest`\n- [ ] New code is covered by unit or system tests.\n- [ ] Docstrings are present on all new public classes and methods (English, Google style).\n- [ ] `uv.lock` is committed if dependencies changed.\n- [ ] The PR description explains **what** changed and **why**.\n- [ ] The branch is rebased on the latest `main`.\n\n### Code standards\n\n- **Formatting:** standard Python conventions (PEP 8).\n- **Docstrings:** English, Google style, on all public symbols.\n- **Type hints:** use them on all new function signatures.\n- **No direct push to `main`** — all changes go through a PR.\n\n### Troubleshooting\n\n**Panda3D / OpenGL errors on headless Linux:**\n```bash\nsudo apt-get install libglu1-mesa libosmesa6\n```\n\n**Subprocess tests open a window — is that expected?**\nYes. `tests/system/test_viewer_subprocess.py` starts the real Panda3D process. Those tests are automatically skipped in headless environments (`DISPLAY` / `WAYLAND_DISPLAY` not set).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flihpc-computational-geometry%2Fbot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flihpc-computational-geometry%2Fbot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flihpc-computational-geometry%2Fbot/lists"}