# Interactive hit-and-run sampling Runs in the browser via [numbl](https://numbl.org) — no install. ## 🎛 [Just the figure →](https://concept-collection.github.io/hitandrun-interactive/#figure/sampler) The figure-only view runs the sampler and drops you straight into the interactive figure (it shows the run's output first, then the figure). The full developer view — file tree, editable code, console — is below. ## ▶ [Open `hitandrun_demo.m`](hitandrun_demo.m) and click **Run** A random 2D region is generated and `N` points are drawn uniformly from it by **hit-and-run**: from the current point, pick a random direction, take the chord where that line crosses the region, and jump to a uniform point on it. Repeat. The figure shows the region and the samples. The region is convex by default, but you can switch to a non-convex **dumbbell** — two convex bulbs joined by a narrow tube — where a single line can enter and leave the region more than once. Controls: - **Samples** — set `N` (re-runs the sampler). - **Resample** — new samples, same region. - **New region** — a fresh region (of the current type). - **non-convex region** — toggle between a convex region and the non-convex dumbbell. The non-convex region uses the slower general sampler, so `N` is capped lower. - **local segment only** *(non-convex only)* — by default the step samples across *every* segment where the line crosses the region (the standard walk, uniform on the whole region); check this to instead sample only within the segment that contains the current point — a local walk that can't jump across the gap between two bulbs, so it does not sample uniformly. - **Play movie** — step through the algorithm: each step draws the chord — one segment for a convex region, possibly several for a non-convex one (or just the local segment) — and the point that landed on it. ## How it works - [`hitandrun_demo.m`](hitandrun_demo.m) — driver: `addpath('helpers')`, seed, call the sampler. - [`hitandrun_sampler.m`](hitandrun_sampler.m) — opens the figure, sends data, handles resample requests, and dispatches to the convex or non-convex sampler. - `helpers/` — [`make_region.m`](helpers/make_region.m) (convex ellipse or dumbbell region), [`hit_and_run.m`](helpers/hit_and_run.m) (convex chord), and [`hit_and_run_general.m`](helpers/hit_and_run_general.m) (arbitrary simple polygon). - `app/` — a single-file React app that draws the region and samples on a canvas. The script and figure talk both ways: the script sends the region + samples via `uihtml(..., 'Data', ...)`, and the controls call back with `sendToMATLAB('resample' | 'newRegion', ...)` (each carrying whether the region is `convex` and, for non-convex, the `local` sampling mode), which re-runs the sampler and returns new points via `sendEventToHTMLSource`. The script is stateless — the figure owns the region and passes it back with each request. ## Convex vs. non-convex `hitandrun_sampler.m` picks the sampler by region type: - **Convex** — [`hit_and_run.m`](helpers/hit_and_run.m) takes the single chord where the line crosses the region (an inward-half-plane intersection). Its loop runs once per sample, so numbl JS-JIT-compiles it to JavaScript — about 30× faster than its interpreter, which is what keeps large `N` instant. The `%!numbl:assert_jit` directive asserts this happens (it errors rather than silently falling back). It relies on numbl's scalar-`rand()` JIT support; `rng(seed)` still controls the shared PRNG. - **Non-convex** — [`hit_and_run_general.m`](helpers/hit_and_run_general.m) finds *every* crossing along the line and keeps the in-region segments (a point-in-polygon test on each interval's midpoint), so concavities are handled correctly. It then samples in one of two modes: **union** (default) picks a point uniformly across all those segments, which samples the whole region uniformly; **local** (the *local segment only* checkbox) restricts to the single segment straddling the current point — a local walk that can't jump the gap between the two bulbs, so it does *not* sample uniformly. The sort + polygon tests don't JIT, so this runs in the interpreter and `N` is capped lower. `make_region(false)` builds the dumbbell, which is not star-shaped and need not contain the origin, so the sampler finds an interior start by rejection rather than assuming one. ## Deploy Pushing to `main` builds the app and publishes the project to GitHub Pages via the [deploy workflow](.github/workflows/deploy.yml).