Skip to content

Commit 61ee9e7

Browse files
authored
Bunch of improvements
2 parents b5b4b39 + 2f4070f commit 61ee9e7

164 files changed

Lines changed: 2968 additions & 4311 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/pip_publish.yml

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
name: Upload Python Package to PyPI when a Release is Created
1+
name: Build Python Wheels
22

33
on:
4+
pull_request:
45
release:
56
types: [created]
67

@@ -13,16 +14,6 @@ jobs:
1314
with:
1415
submodules: recursive
1516

16-
- name: Copy stuff
17-
run: |
18-
rm -rf python_bindings/vendored_deps
19-
rm -rf python_bindings/slamd_src
20-
rm -rf python_bindings/README.md
21-
22-
cp -r vendored_deps python_bindings/vendored_deps
23-
cp -r slamd python_bindings/slamd_src
24-
cp README.md python_bindings/README.md
25-
2617
- name: Set up Python
2718
uses: actions/setup-python@v4
2819
with:
@@ -49,15 +40,13 @@ jobs:
4940
libxkbcommon-devel \
5041
mesa-libEGL-devel \
5142
mesa-libGLES-devel
52-
run: |
53-
cd python_bindings
54-
cibuildwheel --output-dir dist
43+
run: cibuildwheel --output-dir dist
5544

5645
- name: Upload Linux artifact
5746
uses: actions/upload-artifact@v4
5847
with:
5948
name: dist-linux
60-
path: python_bindings/dist
49+
path: dist
6150

6251
build-macos:
6352
name: Build wheels on macOS
@@ -67,16 +56,6 @@ jobs:
6756
with:
6857
submodules: recursive
6958

70-
- name: Copy stuff
71-
run: |
72-
rm -rf python_bindings/vendored_deps
73-
rm -rf python_bindings/slamd_src
74-
rm -rf python_bindings/README.md
75-
76-
cp -r vendored_deps python_bindings/vendored_deps
77-
cp -r slamd python_bindings/slamd_src
78-
cp README.md python_bindings/README.md
79-
8059
- name: Set up Python
8160
uses: actions/setup-python@v4
8261
with:
@@ -88,20 +67,19 @@ jobs:
8867
pip install cibuildwheel
8968
9069
- name: Build wheels with cibuildwheel
91-
run: |
92-
cd python_bindings
93-
cibuildwheel --output-dir dist
70+
run: cibuildwheel --output-dir dist
9471

9572
- name: Upload macOS artifact
9673
uses: actions/upload-artifact@v4
9774
with:
9875
name: dist-macos
99-
path: python_bindings/dist
76+
path: dist
10077

10178
publish:
10279
name: Publish to PyPI
80+
if: github.event_name == 'release'
10381
runs-on: ubuntu-latest
104-
needs: [build-linux, build-macos] # 🔥 waits for both builds
82+
needs: [build-linux, build-macos]
10583
environment:
10684
name: pypi
10785
permissions:

.github/workflows/test_python_build.yml

Lines changed: 0 additions & 59 deletions
This file was deleted.

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@ build/
55
**/*.so
66
**/*__pycache__
77
.cache/
8-
.testvenv/
8+
.testvenv/
9+
dist/
10+
*.egg-info/
11+
_skbuild/
12+
src/slamd/slamd_window

.vscode/settings.json

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
{
22
"clangd.arguments": [
3-
"--compile-commands-dir=python_bindings/build",
4-
// "--compile-commands-dir=examples/build",
3+
"--compile-commands-dir=build/cp312-cp312-linux_x86_64",
54
"--function-arg-placeholders=false",
65
"--tweaks=-Wall",
76
"--tweaks=-Wextra",
@@ -119,8 +118,8 @@
119118
"C_Cpp.inlayHints.autoDeclarationTypes.showOnLeft": false,
120119
"C_Cpp.inlayHints.parameterNames.enabled": true,
121120
"C_Cpp.inlayHints.referenceOperator.enabled": true,
122-
"python.analysis.extraPaths": ["python_bindings/src/"],
123-
"cmake.sourceDirectory": "/home/robert/projects/slam_dunk/examples",
121+
"python.analysis.extraPaths": ["src/"],
122+
"cmake.sourceDirectory": "${workspaceFolder}",
124123
"python.analysis.exclude": [
125124
"**/build/",
126125
"**/.venv/",
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
cmake_minimum_required(VERSION 3.14)
2-
project(myviz_bindings LANGUAGES CXX)
2+
project(slamd LANGUAGES CXX)
33

44
set(CMAKE_CXX_STANDARD 23)
55
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
6-
set(LIB_DIR vendored_deps)
6+
set(LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendored_deps)
77

88
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
99
set(BUILD_SHARED_LIBS OFF)
@@ -36,7 +36,7 @@ add_compile_definitions(SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_OFF)
3636

3737
# EXCLUDE_FROM_ALL prevents vendored deps from installing their own
3838
# files (static archives, examples, tools) into the wheel.
39-
add_subdirectory(slamd_src EXCLUDE_FROM_ALL)
39+
add_subdirectory(slamd EXCLUDE_FROM_ALL)
4040

4141
find_package(Python REQUIRED COMPONENTS Interpreter Development.Module REQUIRED)
4242

@@ -82,7 +82,7 @@ target_link_libraries(bindings
8282
fmt::fmt
8383
)
8484

85-
# slamd_window is excluded from ALL due to EXCLUDE_FROM_ALL on slamd_src,
85+
# slamd_window is excluded from ALL due to EXCLUDE_FROM_ALL on slamd,
8686
# so we need to make bindings depend on it to ensure it gets built.
8787
add_dependencies(bindings slamd_window)
8888

README.md

Lines changed: 58 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,97 @@
1-
![](./images/logo.png)
1+
<img src="./images/logo.png" width="100%">
22

33
---
44

5-
SlamDunk is a powerful and user-friendly Python library for making 3D and 2D visualizations for prototyping, data exploration, and algorithm development.
5+
<img src="./images/galaxy.gif" width="49%"> <img src="./images/lorenz_attractor.gif" width="49%">
66

7-
It is lightweight, built using OpenGL and ImGui.
7+
<img src="./images/double_pendulum.gif" width="49%"> <img src="./images/moving_spheres.gif" width="49%">
88

9-
# Examples
9+
`slamd` is a 3D visualization library for Python. `pip install`, write a few lines, and you have a GPU-accelerated interactive 3D viewer. No event loops, no boilerplate — just set geometry and it shows up.
1010

11-
## Hello world
12-
13-
Here is a simple "hello world" program for a SlamDunk visualization.
14-
15-
```python
16-
import slamd
17-
18-
if __name__ == "__main__":
19-
vis = slamd.Visualizer("Hello world")
20-
21-
scene = vis.scene("scene")
22-
23-
scene.set_object("/origin", slamd.geom.Triad())
24-
25-
vis.hang_forever()
11+
```bash
12+
pip install slamd
2613
```
2714

28-
Running this program results in the following interactive visualization:
29-
![](./images/hello_world.png)
30-
31-
This example highlights the main components of SlamDunk.
32-
33-
The `Visualizer` object maintains the state of the visualization, and starts a TCP server that the visualization window connects to.
15+
## Why slamd?
3416

35-
By default, it spawns a window process that reads from it and displays the visualizations. You can opt out of this with the `spawn` argument, and control the port with the `port` argument.
36-
In this case, you can start a window with the `slamd-window` executable:
17+
Most 3D visualization in Python is either painfully slow (matplotlib's 3D mode), or requires you to learn a massive framework. `slamd` is neither.
3718

38-
```
39-
slamd-window --port [port] --ip [ip]
40-
```
19+
- **Dead simple** — create a visualizer, set geometry, done. The viewer window spawns automatically in a separate process. No event loop, no main thread hijacking, no callbacks.
20+
- **Real 3D rendering** — GPU-accelerated OpenGL. Handles millions of points, animated meshes, and real geometry at interactive framerates. This is not a plot library pretending to do 3D.
21+
- **Pose tree** — objects live in a transform tree (like ROS TF or a scene graph). Set a parent transform and everything underneath moves. Makes articulated and hierarchical scenes trivial.
22+
- **The right primitives** — point clouds, meshes, camera frustums, triads, arrows, polylines, spheres, planes. The stuff you actually need when working with 3D data, robotics, or SLAM.
4123

42-
This client-server architecture allows launching a visualizer a remote server, and connecting to it on your local machine.
24+
## How is this different from Rerun?
4325

44-
A `Scene` object represents and contains a tree of 3D objects, accessed by paths like `/comp1/comp2/comp3`. 3D poses and `Geometry` objects can be assigned with the `set_transform` and `set_object` methods.
26+
`slamd` is a **stateful viewer**, not a logging database. There's no append-only log, no timeline, no timestamps forced onto your data. You have a tree of geometry — you set objects, move them, delete them, and what you see is what's there right now.
4527

46-
`Geometry` objects represent the objects that are displayed in the scene.
28+
Rerun is powerful, but it's a big tool with a lot of concepts. `slamd` does one thing: show your geometry, right now, with minimal API surface. If you want a data recording platform with time-series scrubbing, use Rerun. If you want to throw some geometry on screen and look at it, use `slamd`.
4729

48-
## Multiple scenes
49-
50-
SlamDunk uses ImGui to allow multiple sub-windows with floating and docking support inside the SlamDunk viewer. The following example illustrates creating two windows, each showing its own scene.
30+
## Quick Start
5131

5232
```python
5333
import slamd
54-
import numpy as np
55-
56-
if __name__ == "__main__":
57-
vis = slamd.Visualizer("two windows")
58-
59-
scene1 = vis.scene("scene 1")
60-
scene2 = vis.scene("scene 2")
61-
62-
scene1.set_object("/box", slamd.geom.Box())
63-
64-
scene2.set_object("/origin", slamd.geom.Triad())
65-
66-
scene2.set_object("/ball", slamd.geom.Sphere(2.0))
67-
68-
sphere_transform = np.identity(4, dtype=np.float32)
69-
sphere_transform[:, 3] = np.array([5.0, 1.0, 2.0, 1.0])
70-
71-
scene2.set_transform("/ball", sphere_transform)
72-
73-
vis.hang_forever()
7434

35+
vis = slamd.Visualizer("Hello world")
36+
scene = vis.scene("scene")
37+
scene.set_object("/origin", slamd.geom.Triad())
7538
```
7639

77-
The resulting window looks like this:
78-
79-
![](./images/two_scenes.png)
40+
![](./images/hello_world.gif)
8041

81-
The windows are fully controllable - you can drag them around, make tabs, use them in floating mode, or dock them to the sides like you see in the screenshot. All of this is supported by [ImGui](https://github.com/ocornut/imgui).
42+
That's it. A window opens with an interactive 3D view.
8243

83-
Here is a slightly more elaborate example of something you can do with SlamDunk:
44+
Objects live in a transform tree — move a parent and children follow:
8445

85-
![](./images/moving_mesh.gif)
86-
87-
Or this one:
46+
```python
47+
scene.set_object("/robot/camera/frustum", slamd.geom.CameraFrustum(K, w, h, scale=0.2))
48+
scene.set_object("/robot/lidar/cloud", slamd.geom.PointCloud(pts, colors, point_size))
8849

89-
![](./images/spiral.gif)
50+
# Move the whole robot — camera and lidar come with it
51+
scene.set_transform("/robot", pose)
52+
```
9053

91-
## Supported geometry primitives
54+
## Multiple Windows
9255

93-
### 3D
56+
Create multiple scenes — each gets its own sub-window with ImGui docking. Drag, tab, float, or dock them however you like:
9457

95-
- Camera Frustums (with optional image) (`slamd.geom.CameraFrustum`)
96-
- Arrows/Vectors (`slamd.geom.Arrows`)
97-
- Arbitrary meshes (`slamd.geom.Mesh`)
98-
- Planes (`slamd.geom.Plane`)
99-
- Point Clouds (`slamd.geom.PointCloud`)
100-
- Piecewise linear curves (`slamd.geom.PolyLine`)
101-
- Spheres (`slamd.geom.Sphere`)
102-
- Triads/reference frames (`slamd.geom.Triad`)
58+
```python
59+
vis = slamd.Visualizer("multi-view")
60+
scene1 = vis.scene("RGB camera")
61+
scene2 = vis.scene("point cloud")
10362

104-
## 2D
63+
scene1.set_object("/frustum", slamd.geom.CameraFrustum(K, w, h, img, 1.0))
64+
scene2.set_object("/cloud", slamd.geom.PointCloud(pts, colors, 0.3, 0.5))
65+
```
10566

106-
- Images (`slamd.geom2d.Image`)
107-
- Points (`slamd.geom2d.Points`)
108-
- Piecewise linear curves (`slamd.geom2d.PolyLine`)
109-
- Circles (`slamd.geom2d.Circles`)
67+
![](./images/two_windows.gif)
11068

111-
## Further reading
69+
## Geometry
11270

113-
The examples in `python_examples` showcase some more features of SlamDunk. Some examples are canvases for 2D visualizations and lots of additional geometry primitives such as point clouds, meshes, camera frustums, etc.
71+
- Point clouds — `slamd.geom.PointCloud`
72+
- Meshes — `slamd.geom.Mesh`
73+
- Camera frustums (with image) — `slamd.geom.CameraFrustum`
74+
- Arrows — `slamd.geom.Arrows`
75+
- Polylines — `slamd.geom.PolyLine`
76+
- Spheres — `slamd.geom.Sphere` / `slamd.geom.Spheres`
77+
- Triads — `slamd.geom.Triad`
78+
- Planes — `slamd.geom.Plane`
79+
- Boxes — `slamd.geom.Box`
11480

115-
# Installation
81+
## Installation
11682

117-
Wheels are available on [PyPi](https://pypi.org/project/slamd/), so you can simply
83+
Wheels on [PyPI](https://pypi.org/project/slamd/) for Linux and macOS (Python >= 3.11):
11884

11985
```bash
12086
pip install slamd
12187
```
12288

123-
# Contributions
89+
Only runtime dependency is `numpy >= 1.23`.
90+
91+
## Examples
92+
93+
See [examples/](./examples) for the full set.
94+
95+
## License
12496

125-
All contributions and feedback are welcome and appreciated!
97+
Apache 2.0 — see [LICENSE](./LICENSE).

0 commit comments

Comments
 (0)