Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
65dbde4
Add Examples
mikeingold Aug 31, 2025
da49d18
Create darts.md
mikeingold Aug 31, 2025
a4b128a
Add details
mikeingold Sep 2, 2025
15ed2b8
Update page name
mikeingold Sep 3, 2025
39834d9
Add more details
mikeingold Sep 6, 2025
d079206
Update darts.md
mikeingold Sep 6, 2025
55f403f
Update darts.md
mikeingold Sep 6, 2025
2a15296
Bugfix
mikeingold Sep 6, 2025
d2429c5
Add colors and new struct [skip ci]
mikeingold Sep 11, 2025
2bcf0d4
Add Colors and Distributions to docs Project toml [skip ci]
mikeingold Sep 12, 2025
701d930
Update code
mikeingold Sep 12, 2025
205261d
Add CairoMakie
mikeingold Sep 12, 2025
4cc2406
Update version
mikeingold Sep 12, 2025
2480149
Add some illustration code
mikeingold Sep 12, 2025
8ffa33c
Update Project.toml
mikeingold Sep 12, 2025
94fe86a
Update Julia version to current LTS
mikeingold Sep 12, 2025
c466dbd
Update version bounds
mikeingold Sep 12, 2025
07fc306
Update ref
mikeingold Sep 12, 2025
3f76ec7
Combine code blocks (for now)
mikeingold Sep 12, 2025
68ca4e4
Fill in prior todos
mikeingold Sep 12, 2025
a924103
Bugfix
mikeingold Sep 13, 2025
ac5e67d
Bugfix
mikeingold Sep 13, 2025
d71a078
Bugfix
mikeingold Sep 13, 2025
3dad74a
Bugfix
mikeingold Sep 13, 2025
08a00f0
Bugfix - generate non-svector
mikeingold Sep 13, 2025
a72924d
Bugfix the bugfix
mikeingold Sep 13, 2025
dec7ea9
Set axes limits for LScene
mikeingold Sep 13, 2025
c9a97c0
Switch from LScene to Axis3
mikeingold Sep 13, 2025
ffcdcfd
Switch to 2D viz of dartboard
mikeingold Sep 24, 2025
f41836c
Add GeometryBasics
mikeingold Sep 24, 2025
5a5eec9
Add _Point2f method
mikeingold Sep 24, 2025
14f3dc4
Temporary standalone script
mikeingold Oct 9, 2025
2f39a80
Minor cleanup and reorganization
mikeingold Nov 5, 2025
926e347
Update Markdown page with new script code
mikeingold Nov 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- uses: actions/checkout@v4
- uses: julia-actions/setup-julia@v2
with:
version: '1.9'
version: '1.10'
- uses: julia-actions/cache@v2
- name: Install dependencies
run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
Expand Down
7 changes: 7 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
[deps]
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
MeshIntegrals = "dadec2fd-bbe0-4da4-9dbe-476c782c8e47"
Meshes = "eacbb407-ea5a-433e-ab97-5258b1ca43fa"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[compat]
BenchmarkTools = "1"
CairoMakie = "0.15"
Colors = "0.13"
Distributions = "0.25"
Documenter = "1"
Meshes = "0.53, 0.54"
Unitful = "1.19"
Expand Down
3 changes: 3 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ makedocs(
"Support Status" => "support.md",
"Tips" => "tips.md"
],
"Examples" => [
"Darts Strategy Analysis" => "examples/darts.md"
],
"Developer Notes" => [
"Changelog" => "developer/CHANGELOG.md",
"How it Works" => "developer/how_it_works.md",
Expand Down
19 changes: 19 additions & 0 deletions docs/src/examples/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[deps]
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
MeshIntegrals = "dadec2fd-bbe0-4da4-9dbe-476c782c8e47"
Meshes = "eacbb407-ea5a-433e-ab97-5258b1ca43fa"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[compat]
BenchmarkTools = "1"
CairoMakie = "0.15"
Colors = "0.13"
Distributions = "0.25"
Documenter = "1"
Meshes = "0.53, 0.54"
Unitful = "1.19"
julia = "1.9"
109 changes: 109 additions & 0 deletions docs/src/examples/darts.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using CairoMakie
using Colors
using Distributions
using Meshes
using MeshIntegrals
using Unitful
using Unitful.DefaultSymbols: mm, m


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JuliaFormatter] reported by reviewdog 🐶

Suggested change

################################################################################
# Geometry Utils
################################################################################

# Define a plane (wall) on which the dartboard rests
dartboard_center = Meshes.Point(0m, 0m, 1.5m)
dartboard_plane = Plane(dartboard_center, Meshes.Vec(1, 0, 0))
point(t, ϕ) = dartboard_plane(t * sin(ϕ), t * cos(ϕ))
point(r::Unitful.Length, ϕ) = point(ustrip(u"m", r), ϕ)

# Score-earning areas where darts can land
struct ScoredRegion{G, C}
geometry::G
points::Int64
color::C
end

# A sectoral geometry bounded by constant r and ϕ limits
struct Sector{L <: Unitful.Length, A}
r_inner::L
r_outer::L
ϕ_a::A
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
ϕ_a::A
ϕ_a::A

ϕ_b::A
end

# Sector -> Ngon
function _Ngon(sector::Sector; N=32)
ϕs = range(sector.ϕ_a, sector.ϕ_b, length=N)
Comment on lines +36 to +37
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
function _Ngon(sector::Sector; N=32)
ϕs = range(sector.ϕ_a, sector.ϕ_b, length=N)
function _Ngon(sector::Sector; N = 32)
ϕs = range(sector.ϕ_a, sector.ϕ_b, length = N)

arc_o = [point(sector.r_outer, ϕ) for ϕ in ϕs]
arc_i = [point(sector.r_inner, ϕ) for ϕ in reverse(ϕs)]
return Meshes.Ngon(arc_o..., arc_i...)
end


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JuliaFormatter] reported by reviewdog 🐶

Suggested change

################################################################################
# Construct Dartboard ScoredRegions
################################################################################

# Sectorize the board
# scores
ring_pts = [20, 1, 18, 4, 13, 6, 10, 15, 2, 17, 3, 19, 7, 16, 8, 11, 14, 9, 12, 5]
board_points = hcat(ring_pts, (3 .* ring_pts), ring_pts, (2 .* ring_pts))
# colors
ring_c1 = repeat([colorant"black", colorant"white"], 10)
ring_c2 = repeat([colorant"red", colorant"green"], 10)
board_colors = hcat(ring_c1, ring_c2, ring_c1, ring_c2)
# geometries
Δϕ = 2π/20
ϕas = range(0, 2π - Δϕ, length=20) .- (Δϕ / 2)
ϕbs = range(0, 2π - Δϕ, length=20) .+ (Δϕ / 2)
Comment on lines +57 to +59
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
Δϕ = 2π/20
ϕas = range(0, 2π - Δϕ, length=20) .- (Δϕ / 2)
ϕbs = range(0, 2π - Δϕ, length=20) .+ (Δϕ / 2)
Δϕ = 2π / 20
ϕas = range(0, 2π - Δϕ, length = 20) .- (Δϕ / 2)
ϕbs = range(0, 2π - Δϕ, length = 20) .+ (Δϕ / 2)

ϕs = Iterators.zip(ϕas, ϕbs)
rs = [ (16mm, 99mm), (99mm, 107mm), (107mm, 162mm), (162mm, 170mm) ]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
rs = [ (16mm, 99mm), (99mm, 107mm), (107mm, 162mm), (162mm, 170mm) ]
rs = [(16mm, 99mm), (99mm, 107mm), (107mm, 162mm), (162mm, 170mm)]

board_ngons = map(((ϕs, rs),) -> _Ngon(Sector(rs..., ϕs...)), Iterators.product(ϕs, rs))

# Consolidate the Sectors
sector_data = Iterators.zip(board_ngons, board_points, board_colors)
board_regions = map(args -> ScoredRegion(args...), sector_data)

# Center region
bullseye_inner = ScoredRegion(Meshes.Circle(dartboard_plane, (6.35e-3)m), 50, colorant"red")
bullseye_outer = ScoredRegion(_Ngon(Sector(6.35mm, 16.0mm, 0.0, 2π)), 25, colorant"green")

# Get set of all regions
all_regions = vcat(vec(board_regions), bullseye_inner, bullseye_outer)


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JuliaFormatter] reported by reviewdog 🐶

Suggested change

################################################################################
# Makie Utils
################################################################################

# To Makie-compatible GeometryBasics types
_Point2f(p::Meshes.Point) = Point2f(ustrip.(u"m", (p.coords.y, p.coords.z))...)
_Point3f(p::Meshes.Point) = Point3f(ustrip.(u"m", (p.coords.x, p.coords.y, p.coords.z))...)

# To Makie-compatible polygons
_poly(circle::Meshes.Circle; N=32) = [(_Point3f(circle(t)) for t in range(0, 1, length=N))...]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
_poly(circle::Meshes.Circle; N=32) = [(_Point3f(circle(t)) for t in range(0, 1, length=N))...]
function _poly(circle::Meshes.Circle; N = 32)
[(_Point3f(circle(t)) for t in range(0, 1, length = N))...]
end

_poly(ngon::Meshes.Ngon) = [(_Point3f(pt) for pt in ngon.vertices)...]
_poly2d(circle::Meshes.Circle; N=32) = [(_Point2f(circle(t)) for t in range(0, 1, length=N))...]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
_poly2d(circle::Meshes.Circle; N=32) = [(_Point2f(circle(t)) for t in range(0, 1, length=N))...]
function _poly2d(circle::Meshes.Circle; N = 32)
[(_Point2f(circle(t)) for t in range(0, 1, length = N))...]
end

_poly2d(ngon::Meshes.Ngon) = [(_Point2f(pt) for pt in ngon.vertices)...]


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JuliaFormatter] reported by reviewdog 🐶

Suggested change

################################################################################
# Figure - Dartboard
################################################################################

# Illustrate the dartboard
fig = Figure()
ax = Axis(fig[1, 1], xlabel="y [m]", ylabel="z [m]")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
ax = Axis(fig[1, 1], xlabel="y [m]", ylabel="z [m]")
ax = Axis(fig[1, 1], xlabel = "y [m]", ylabel = "z [m]")

ax.aspect = DataAspect()
for region in all_regions
poly!(ax, _poly2d(region.geometry), color=region.color)

Comment on lines +100 to +101
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
poly!(ax, _poly2d(region.geometry), color=region.color)
poly!(ax, _poly2d(region.geometry), color = region.color)

# Write score label on geometry
centerPt = centroid(region.geometry)
center = ustrip.(u"m", [centerPt.coords.y, centerPt.coords.z])
text!(ax, string(region.points), position=Point2f(center...), align=(:center,:center), color=:blue, fontsize=10)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
text!(ax, string(region.points), position=Point2f(center...), align=(:center,:center), color=:blue, fontsize=10)
text!(ax, string(region.points), position = Point2f(center...),
align = (:center, :center), color = :blue, fontsize = 10)

end

fig
save("dartboard.png", fig)
147 changes: 147 additions & 0 deletions docs/src/examples/darts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Darts (Draft)

Steps
- Construct a set of geometries representing a dartboard with individual sector scores
- Develop a model of the dart trajectory with probability density distribution
- Use integration over each geometry to determine the probabilities of particular outcomes
- Calculate expected value for the throw, repeat for other distributions to compare strategies

```@example darts

```

## Modeling the Dartboard

Model the dartboard
```@example darts
using CairoMakie
using Colors
using Distributions
using Meshes
using MeshIntegrals
using Unitful
using Unitful.DefaultSymbols: mm, m


################################################################################
# Geometry Utils
################################################################################

# Define a plane (wall) on which the dartboard rests
dartboard_center = Meshes.Point(0m, 0m, 1.5m)
dartboard_plane = Plane(dartboard_center, Meshes.Vec(1, 0, 0))
point(t, ϕ) = dartboard_plane(t * sin(ϕ), t * cos(ϕ))
point(r::Unitful.Length, ϕ) = point(ustrip(u"m", r), ϕ)

# Score-earning areas where darts can land
struct ScoredRegion{G, C}
geometry::G
points::Int64
color::C
end

# A sectoral geometry bounded by constant r and ϕ limits
struct Sector{L <: Unitful.Length, A}
r_inner::L
r_outer::L
ϕ_a::A
ϕ_b::A
end

# Sector -> Ngon
function _Ngon(sector::Sector; N=32)
ϕs = range(sector.ϕ_a, sector.ϕ_b, length=N)
arc_o = [point(sector.r_outer, ϕ) for ϕ in ϕs]
arc_i = [point(sector.r_inner, ϕ) for ϕ in reverse(ϕs)]
return Meshes.Ngon(arc_o..., arc_i...)
end


################################################################################
# Construct Dartboard ScoredRegions
################################################################################

# Sectorize the board
# scores
ring_pts = [20, 1, 18, 4, 13, 6, 10, 15, 2, 17, 3, 19, 7, 16, 8, 11, 14, 9, 12, 5]
board_points = hcat(ring_pts, (3 .* ring_pts), ring_pts, (2 .* ring_pts))
# colors
ring_c1 = repeat([colorant"black", colorant"white"], 10)
ring_c2 = repeat([colorant"red", colorant"green"], 10)
board_colors = hcat(ring_c1, ring_c2, ring_c1, ring_c2)
# geometries
Δϕ = 2π/20
ϕas = range(0, 2π - Δϕ, length=20) .- (Δϕ / 2)
ϕbs = range(0, 2π - Δϕ, length=20) .+ (Δϕ / 2)
ϕs = Iterators.zip(ϕas, ϕbs)
rs = [ (16mm, 99mm), (99mm, 107mm), (107mm, 162mm), (162mm, 170mm) ]
board_ngons = map(((ϕs, rs),) -> _Ngon(Sector(rs..., ϕs...)), Iterators.product(ϕs, rs))

# Consolidate the Sectors
sector_data = Iterators.zip(board_ngons, board_points, board_colors)
board_regions = map(args -> ScoredRegion(args...), sector_data)

# Center region
bullseye_inner = ScoredRegion(Meshes.Circle(dartboard_plane, (6.35e-3)m), 50, colorant"red")
bullseye_outer = ScoredRegion(_Ngon(Sector(6.35mm, 16.0mm, 0.0, 2π)), 25, colorant"green")

# Get set of all regions
all_regions = vcat(vec(board_regions), bullseye_inner, bullseye_outer)


################################################################################
# Makie Utils
################################################################################

# To Makie-compatible GeometryBasics types
_Point2f(p::Meshes.Point) = Point2f(ustrip.(u"m", (p.coords.y, p.coords.z))...)
_Point3f(p::Meshes.Point) = Point3f(ustrip.(u"m", (p.coords.x, p.coords.y, p.coords.z))...)

# To Makie-compatible polygons
_poly(circle::Meshes.Circle; N=32) = [(_Point3f(circle(t)) for t in range(0, 1, length=N))...]
_poly(ngon::Meshes.Ngon) = [(_Point3f(pt) for pt in ngon.vertices)...]
_poly2d(circle::Meshes.Circle; N=32) = [(_Point2f(circle(t)) for t in range(0, 1, length=N))...]
_poly2d(ngon::Meshes.Ngon) = [(_Point2f(pt) for pt in ngon.vertices)...]


################################################################################
# Figure - Dartboard
################################################################################

# Illustrate the dartboard
fig = Figure()
ax = Axis(fig[1, 1], xlabel="y [m]", ylabel="z [m]")
ax.aspect = DataAspect()
for region in all_regions
poly!(ax, _poly2d(region.geometry), color=region.color)

# Write score label on geometry
centerPt = centroid(region.geometry)
center = ustrip.(u"m", [centerPt.coords.y, centerPt.coords.z])
text!(ax, string(region.points), position=Point2f(center...), align=(:center,:center), color=:blue, fontsize=10)
end
fig
```

## Modeling the Dart Trajectory

Define a probability distribution for where the dart will land
```
# TODO
dist = MvNormal(μs, σs)
```

Integrand function is the distribution's PDF value at any particular point
```
# TODO
function integrand(p::Point)
v_error = dist_center - p
pdf(dist, v_error)
end
```

Example image of trajectory probability distribution on board

## Strategy Evaluation

Use these tools to evaluate different aiming/throwing parameters and their impact on expected scores.
Loading