function G = triangle_geometry(P) % TRIANGLE_GEOMETRY Node polyline of the open triangle centerline. % % An equilateral triangle of side side_length_m in the x-y plane, apex up: % base from V2 (bottom left) to V3 (bottom right) along y = 0, apex V1 above % the origin. The rod is open at the bottom-left corner: gap_m of arclength % is removed there, half from the base and half from the left leg, so the % centerline runs A -> V3 -> V1 -> B counterclockwise, where A and B sit % gap_m / 2 from V2 along their legs. Total rod length is 3 L - gap. % % The polyline is discretized into about n_elements equal-length elements, % with the two closed corners landing exactly on nodes. Arclength fraction 0 % is the free end on the base, 1 the free end on the left leg; strike_pos and % roll_pos2 are expressed in this coordinate. % % Returns G with: % nodes 2 x nn node coordinates (m) % sfrac 1 x nn arclength fraction of each node % totalLen rod arclength (m) % nn, ne node count and per-leg element counts (1 x 3) L = P.side_length_m; g = min(P.gap_m, 0.8 * L); V1 = [0; L * sqrt(3) / 2]; V2 = [-L / 2; 0]; V3 = [L / 2; 0]; e1 = (V3 - V2) / L; e3 = (V2 - V1) / L; A = V2 + e1 * (g / 2); B = V2 - e3 * (g / 2); starts = [A, V3, V1]; stops = [V3, V1, B]; lens = [L - g / 2, L, L - g / 2]; total = lens(1) + lens(2) + lens(3); ne = zeros(1, 3); for k = 1:3 ne(k) = max(2, round(P.n_elements * lens(k) / total)); end nn = ne(1) + ne(2) + ne(3) + 1; nodes = zeros(2, nn); sarc = zeros(1, nn); nodes(:, 1) = A; idx = 1; acc = 0; for k = 1:3 for j = 1:ne(k) idx = idx + 1; frac = j / ne(k); nodes(:, idx) = starts(:, k) + (stops(:, k) - starts(:, k)) * frac; sarc(idx) = acc + lens(k) * frac; end acc = acc + lens(k); end G.nodes = nodes; G.sfrac = sarc / total; G.totalLen = total; G.nn = nn; G.ne = ne; end