A desktop GUI tool to visualize and understand 3D coordinate frames, their parent-child hierarchies, and transformations using a simple DSL. Built with PySide6 and VisPy.
FramesSim_v8/
├─ AXIS_LABELS_GUIDE.md
├─ dsl_parser.py
├─ frame_visual.py
├─ frames_model.py
├─ main.py
├─ math_se3.py
├─ README.md ← you are here
├─ ui_helper_functions.py
└─ ui_main_window.py
- Visualizes coordinate frames as RGB axes (X=Red, Y=Green, Z=Blue)
- Lets you build hierarchies of frames with a root “Universe” frame (U)
- Defines frame poses using a simple text DSL: Rot(axis, deg) and Trans(x, y, z)
- Supports both local and world modes for rotations/translations
- Adds points attached to frames and shows their links to parent frames
- Animates a frame from identity to its current pose (1-second demo)
- Provides camera controls (Home, Focus) and grid toggle
- Optional 3‑plane reference grids (XY, XZ, YZ) that toggle together
- Data model (
frames_model.py): keeps a dictionary of FrameNode objects, each with a parent and a local 4×4 transform. Computes world transforms by chaining parent→child. - DSL parser (
dsl_parser.py): parses strings likeRot(z, 90) Trans(1,0,0)into tokens. - SE(3) math (
math_se3.py): composes token lists into 4×4 matrices with selectable local/world modes for both translation and rotation. - Visuals (
frame_visual.py): draws axes and labels using VisPy visuals; also supports point visuals. - UI (
ui_main_window.py+ui_helper_functions.py): PySide6 window with a VisPy canvas on the left and controls on the right. Mix-in holds helper logic. - Entry point (
main.py): wires PySide6 and VisPy and launches the app.
- FrameNode: name, parent, tokens, local_M (4×4), and optional visual.
- FramesModel:
add_frame,set_expr,set_trans_mode,set_rot_mode, andworld_M(name). - Universe frame
Uis created at startup; its transform is identity.
World transform is computed recursively:
world_M(C) = world_M(B) @ local_M(C)
- DSL tokens:
- Rotation:
('rot', ('x'|'y'|'z', degrees)) - Translation:
('trans', (x, y, z))
- Rotation:
- Composition rules:
- Translation mode
- world:
M = T @ M - local:
M = M @ T
- world:
- Rotation mode
- world:
M = R @ M(rotate around world axes) - local:
M = M @ R(rotate around frame axes)
- world:
- Translation mode
- Each frame draws three arrows (RGB) and a text label above the origin.
apply_transform(M)directly updates world-space positions of the arrows and label.PointVisualhides the arrows and shows only a label (used for points).
- Left: VisPy SceneCanvas with TurntableCamera and an optional grid.
- Right: controls for frames list, points list, add/update/delete, mode selectors, and live matrix views for the selected frame and point.
- Link visualization:
- Yellow line: selected frame to its parent
- Cyan line: selected point to its parent frame
UIHelperMixincentralizes: applying transforms, refreshing matrices, drawing links, and the animation step.- Matrices are shown using monospaced QLabel blocks (cleaner than text editors) and are selectable for copy.
- Create a virtual environment (recommended)
- Windows (cmd):
python -m venv .venv
.venv\Scripts\activate
- Install dependencies
pip install -r requirements.txt
- Run the app
python main.py
If VisPy complains about backends, the app configures PySide6 via vispy_app.use_app('pyside6') in main.py.
- Add a frame:
- Enter Name, choose Parent, and type an Expr (DSL). Click “Add Frame”.
- Update a frame:
- Select a frame (not U), edit Expr, click “Update Selected”.
- Delete a frame/point:
- Select it and click the respective “Delete” button (U cannot be deleted).
- Add a point:
- Tools → Add Point (Ctrl+P), choose parent frame and enter translations.
- Toggle grid:
- Tools → Toggle Grid (Ctrl+G)
- Shows/hides all three major planes: XY (z=0), XZ (y=0), YZ (x=0)
- Animate selected frame:
- Tools → Animate Selected Frame (Ctrl+A)
- Camera:
- View → Home (H) resets view
- View → Focus centers the camera on the selected frame
- Rotations (degrees)
- Keywords are case-insensitive:
Rot,rot,ROTall work
- Keywords are case-insensitive:
Rot(x, 90)
Rot(y, -45.5)
Rot(z, 180)
rot(Z, 30)
- Translations
- Keywords are case-insensitive:
Trans,trans,TRANSall work
- Keywords are case-insensitive:
Trans(1, 2, 3)
trans(0.5, 0, -2)
- Chaining
Rot(z, 90) Trans(1, 0, 0) Rot(x, 45)
Modes affect order of multiplication:
- Translation mode = world → pre-multiply T
- Translation mode = local → post-multiply T
- Rotation mode = world → pre-multiply R
- Rotation mode = local → post-multiply R
- Animation demo interpolates a selected frame from identity to its current local transform over ~1s.
- The rotation block is re-orthonormalized using SVD at every step to avoid drift.
- Mixed-frame reference edge case: generating output may fail if one rotation/translation in an expression is intended relative to the current frame while another is explicitly relative to the Universe frame (U) within the same context. Consider sticking to a single mode per expression for now, or split operations.
- Add view presets (front, back, left, right, top, isometric)
- Add saving/loading scenes (JSON)
- Add snapping, gizmos, or manipulators in the 3D view
- Add export of transforms/frames for other tools
- Add tests for DSL parsing and matrix composition
Built with python using PySide6, VisPy, and NumPy.