Skip to content

Commit 86e6140

Browse files
authored
Merge pull request #6 from HolyLab/as/docs_with_glmakie
More Makie integration
2 parents 4f34f37 + 432b8c0 commit 86e6140

File tree

12 files changed

+549
-36
lines changed

12 files changed

+549
-36
lines changed

.github/workflows/CI.yml

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,33 +45,36 @@ jobs:
4545
token: ${{ secrets.CODECOV_TOKEN }}
4646
fail_ci_if_error: false
4747
docs:
48-
name: Documentation
48+
name: Build and deploy documentation
4949
runs-on: ubuntu-latest
50-
permissions:
51-
actions: write # needed to allow julia-actions/cache to proactively delete old caches that it has created
52-
contents: write
53-
statuses: write
5450
steps:
51+
- name: Install binary dependencies
52+
run: sudo apt-get update && sudo apt-get install -y xorg-dev mesa-utils xvfb libgl1 freeglut3-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxext-dev
5553
- uses: actions/checkout@v4
56-
- uses: julia-actions/setup-julia@v2
54+
- name: Download all workflow run artifacts
55+
uses: actions/download-artifact@v4
56+
- uses: julia-actions/setup-julia@latest
5757
with:
5858
version: '1'
5959
- uses: julia-actions/cache@v2
60-
- name: Configure doc environment
61-
shell: julia --project=docs --color=yes {0}
60+
- name: Install documentation dependencies
6261
run: |
63-
using Pkg
64-
Pkg.develop(PackageSpec(path=pwd()))
65-
Pkg.instantiate()
66-
- uses: julia-actions/julia-buildpkg@v1
67-
- uses: julia-actions/julia-docdeploy@v1
62+
xvfb-run -s '-screen 0 1024x768x24' julia --project=docs -e '
63+
using Pkg
64+
Pkg.develop(PackageSpec(path=pwd()))
65+
Pkg.add(name = "DocumenterVitepress", rev = "master")
66+
Pkg.instantiate()'
6867
env:
69-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
70-
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}
71-
- name: Run doctests
72-
shell: julia --project=docs --color=yes {0}
73-
run: |
74-
using Documenter: DocMeta, doctest
75-
using FlyThroughPaths
76-
DocMeta.setdocmeta!(FlyThroughPaths, :DocTestSetup, :(using FlyThroughPaths); recursive=true)
77-
doctest(FlyThroughPaths)
68+
DISPLAY: ':0'
69+
- name: Build and deploy
70+
env:
71+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # If authenticating with GitHub Actions token
72+
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # If authenticating with SSH deploy key
73+
DISPLAY: ':0'
74+
run: xvfb-run -s '-screen 0 1024x768x24' julia --project=docs/ docs/make.jl deploy
75+
- name: Run doctests
76+
run: julia --project=docs -e '
77+
using Documenter;
78+
using FlyThroughPaths;
79+
Documenter.DocMeta.setdocmeta!(FlyThroughPaths, :DocTestSetup, :(using FlyThroughPaths); recursive=true);
80+
Documenter.doctest(FlyThroughPaths);'

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,22 +139,22 @@ You need to load the visualization package, e.g., `using GLMakie`, in your sessi
139139

140140
This can be handy for constructing a path, for example you can interactively set the approximate position and view parameters and then query them for use by the tools above.
141141

142-
```
142+
```julia
143143
state = capture_view(scene)
144144
```
145145

146146
`state` is a `ViewState` object.
147147

148148
### Setting the current view state
149149

150-
```
150+
```julia
151151
oldstate = set_view!(camera, path, t)
152152
```
153153

154154
This updates the current `camera` settings from `path` at time `t`.
155155

156156
### Displaying the path
157157

158-
```
158+
```julia
159159
plot(path)
160160
```

docs/Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
[deps]
2+
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
23
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
34
FlyThroughPaths = "c11bb9a7-2755-425a-88f3-ebe93bbdb91f"
5+
GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
6+
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
7+
MakieCore = "20f20a25-4f0e-4fdf-b5d1-57303727442b"

docs/make.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ makedocs(;
1414
),
1515
pages=[
1616
"Home" => "index.md",
17+
"Makie integration" => "makie.md",
18+
"Developer documentation" => "devdocs.md"
1719
],
20+
warnonly=true,
1821
)
1922

2023
deploydocs(;
2124
repo="github.com/HolyLab/FlyThroughPaths.jl",
2225
devbranch="main",
26+
push_preview=true,
2327
)

docs/src/devdocs.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Developer documentation
2+
3+
## Implementing support for FlyThroughPaths
4+
5+
FlyThroughPaths operates on the [`ViewState`](@ref) model. In order to implement support for this in a plotting package, you must implement dispatches for the following two functions:
6+
- `capture_view(obj)::ViewState`: extract the current `ViewState`, i.e., camera settings, from `obj`.
7+
- `set_view!(obj, viewstate::ViewState)`: set the camera to the given `ViewState`.
8+
9+
Integration is already implemented for Makie; you can see that in `ext/FlyThroughPathsMakieExt.jl`. The first ~20 lines are the most instructive, beyond which lie utility functions and visualization specializations.
10+
11+
## The `PathChange` interface
12+
13+
```@docs
14+
PathChange
15+
duration
16+
```

docs/src/index.md

Lines changed: 137 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,143 @@ CurrentModule = FlyThroughPaths
66

77
Documentation for [FlyThroughPaths](https://github.com/HolyLab/FlyThroughPaths.jl).
88

9-
```@index
9+
10+
All of the examples below assume you've loaded the package with `using FlyThroughPaths`.
11+
12+
# Quick start
13+
14+
## Generic tools
15+
16+
### Representation of paths and view state
17+
18+
Paths are parametrized by time `t`, represented in units of seconds. All paths implicitly start at `t=0`.
19+
20+
The representation of view state is independent of any particular plotting package, although our parametrization is inspired by [Makie's 3D camera](https://docs.makie.org/stable/explanations/cameras/#3d_camera):
21+
22+
- `eyeposition`: the 3d coordinates of the camera
23+
- `lookat`: the 3d coordinates of the point of the camera's "focus" (center of gaze)
24+
- `upvector`: the 3d direction that will correspond to the top of the view. Any component of this vector in the direction of `lookat - eyeposition` is ignored/discarded.
25+
- `fov`: the angle (in degrees) of the cone centered on `lookat - eyeposition` that should be captured.
26+
27+
Set these as follows:
28+
29+
```@repl main
30+
using FlyThroughPaths
31+
state = ViewState(eyeposition=[-10, 0, 0], lookat=[0, 0, 0], upvector=[0, 0, 1], fov=45)
32+
```
33+
34+
You can set just a subset of these:
35+
```@repl main
36+
newstate = ViewState(eyeposition=[-5, 0, 0])
37+
```
38+
39+
This syntax is often used for updating a previous view; for the unspecified settings, the previous value is left intact.
40+
41+
42+
### Initializing a path
43+
44+
```@repl main
45+
path = Path(state)
46+
```
47+
48+
The path starts at `state` at time `t=0`.
49+
50+
### Evaluating at a particular time
51+
52+
Once you have a path, you can get the current `ViewState` with `path(t)`:
53+
54+
```@repl main
55+
path(0)
56+
57+
path(10)
58+
```
59+
60+
So far, nothing much is happening. Things get more interesting when we add movements.
61+
62+
### Holding steady
63+
64+
The simplest thing you can do is insert a pause:
65+
66+
```@repl main
67+
path2 = path * Pause(5)
68+
```
69+
70+
The view will hold steady for 5 seconds. Typically you add `Pause` when you also plan to add other movements later.
71+
72+
### Moving the camera, option 1: constrained movements
73+
74+
This option is typically used for things like rotations around a center point.
75+
76+
```@repl main
77+
path2 = path * ConstrainedMove(5, newstate; constraint=:none, speed=:constant)
1078
```
1179

12-
```@autodocs
13-
Modules = [FlyThroughPaths]
80+
This indicates that over a 5-second period, the camera state gradually adopts any values specified in `newstate`.
81+
82+
```@repl main
83+
path2(0)
84+
path2(5)
85+
path2(2.5)
86+
```
87+
88+
Keyword options include:
89+
90+
- `constraint` (`:none` or `:rotation`): specify a value to keep constant during motion. `:rotation` performs a rotation around `lookat`. Note that if the separation between `eyeposition` and `lookat` is not constant, then the trajectory will be elliptical rather than circular.
91+
- `speed` controls how the change is made across time:
92+
- `:constant`: speed is instantaneously set to a new constant value that will arrive at the endpoint at the specified time
93+
- `:sinusoidal`: speed will initially increase (starting at a speed of 0), achieve a maximum at the midpoint, and then decrease back to 0.
94+
95+
96+
### Moving the camera, option 2: Bezier movements
97+
98+
With this option, you can approximately simulate the feeling of flight, preserving momentum:
99+
100+
```
101+
path2 = path * BezierMove(Δt::Real, P1::ViewState, P2::ViewState...)
102+
```
103+
104+
where a `bezier` path is specified as indicated in this diagram:
105+
106+
![bezier diagram](https://upload.wikimedia.org/wikipedia/commons/thumb/d/d0/Bezier_curve.svg/640px-Bezier_curve.svg.png)
107+
108+
The starting state, `P0` in the diagram, is taken from the endpoint of `path`. Over the next `Δt` seconds, one then moves towards the last `ViewState` argument of `bezier`, orienting successively towards any prior arguments. Probably the most robust option is to use `bezier(Δt, P1, P2, P3)`, which can be interpreted as "depart `P0` traveling towards `P1`, and arrive at `P3` as if you had come from `P2`." The view does not actually pass through `P1` and `P2`, but these set the initial and final tangents of the curve.
109+
110+
To see this in action, let's create a move that "rotates" around the origin but moves outward (to a more distant orbit) on its way there:
111+
112+
```@repl main
113+
move = BezierMove(5, ViewState(eyeposition=[0, 10, 0]), [ViewState(eyeposition=[-20, 20, 0])])
114+
path2 = path * move;
115+
path2(2.5)
116+
```
117+
118+
## Backend-specific tools
119+
120+
These require interaction with a plotting package supported by one of the extensions. Currently supported:
121+
122+
- [Makie](https://docs.makie.org/stable/)
123+
124+
You need to load the visualization package, e.g., `using GLMakie`, in your session before any of the commands below will work.
125+
126+
### Capturing the current view state
127+
128+
This can be handy for constructing a path, for example you can interactively set the approximate position and view parameters and then query them for use by the tools above.
129+
130+
```julia
131+
state = capture_view(scenelike::Union{Scene, LScene})
132+
```
133+
134+
`state` is a `ViewState` object.
135+
136+
### Setting the current view state
137+
138+
```julia
139+
oldstate = set_view!(scenelike, path, t)
140+
```
141+
142+
This updates the current `camera` settings from `path` at time `t`.
143+
144+
### Displaying the path
145+
146+
```julia
147+
plot(path)
14148
```

0 commit comments

Comments
 (0)