d9d003fAdd non-convex (star) regions with a general hit-and-run samplerJeremy Magland 1function [vx, vy] = make_region(convex)
2%MAKE_REGION Random 2D sampling region, returned as CCW vertices (VX, VY).
fcc5958Generate convex region without convhull (fixes figure-view startup race)Jeremy Magland 3% MAKE_REGION(true) — a convex polygon (vertices on a random ellipse).
d9d003fAdd non-convex (star) regions with a general hit-and-run samplerJeremy Magland 4% MAKE_REGION(false) — a non-convex star polygon (star-shaped about the
5% origin, so the origin is a valid interior start point).
6if nargin < 1 || isempty(convex)
7 convex = true;
8end
10if convex
11 [vx, vy] = convex_region();
12else
13 [vx, vy] = star_region();
14end
16% CCW so the interior is to the left of each edge.
17if signed_area(vx, vy) < 0
18 vx = vx(end:-1:1);
19 vy = vy(end:-1:1);
20end
21end
23function [vx, vy] = convex_region()
fcc5958Generate convex region without convhull (fixes figure-view startup race)Jeremy Magland 24% Vertices at increasing angles on an anisotropic, randomly rotated ellipse.
25% Points taken in angular order on the ellipse are always in convex position,
26% so the polygon is convex by construction — no convhull backend needed (the
27% browser worker may not have finished loading it when the figure view
28% auto-runs the script). Even angular slots + bounded jitter keep the angles
29% ordered and the edges non-degenerate while still random.
30m = 6 + randi(4); % 7..10 vertices
31slot = 2 * pi / m;
32ang = (0:m - 1).' * slot + (rand(m, 1) - 0.5) * slot * 0.8;
33ex = 1.4 * cos(ang); % on an ellipse (anisotropic)
34ey = 1.0 * sin(ang);
35phi = 2 * pi * rand; % random orientation
36vx = cos(phi) * ex - sin(phi) * ey;
37vy = sin(phi) * ex + cos(phi) * ey;
40function [vx, vy] = star_region()
41% Spikes at sorted angles, alternating outer/inner radius. Small angle jitter
42% keeps the angles ordered, so the polygon stays simple and star-shaped about
43% the origin (lines through interior points can still leave and re-enter it).
44spikes = 4 + randi(4); % 5..8 spikes
45k = 2 * spikes;
46step = 2 * pi / k;
47ang = (0:k - 1) * step + (rand(1, k) - 0.5) * step * 0.6;
48r = zeros(1, k);
49r(1:2:k) = 0.9 + 0.4 * rand(1, numel(1:2:k)); % outer
50r(2:2:k) = 0.35 + 0.2 * rand(1, numel(2:2:k)); % inner
51vx = (1.3 * r .* cos(ang)).';
52vy = (1.0 * r .* sin(ang)).';
55function A = signed_area(vx, vy)
56%SIGNED_AREA Shoelace area; positive when the vertices run counterclockwise.
57n = numel(vx);
58A = 0;
59for i = 1:n
60 j = mod(i, n) + 1;
61 A = A + (vx(i) * vy(j) - vx(j) * vy(i));
62end
63A = A / 2;
64end