function slice = build_z_slice(mesh, field, z0, axis)
%BUILD_Z_SLICE  Cut 3D tet mesh by plane and sample scalar field on slice.
%   axis: 1=x, 2=y, 3=z (default 3)
if nargin < 4
    axis = 3;
end
if axis == 1
    ia = 2; ib = 3;
elseif axis == 2
    ia = 1; ib = 3;
else
    ia = 1; ib = 2;
end

xs = [];
ys = [];
vals = [];
elems = [];
nodeCount = 0;
tol = 1e-9;

for n = 1:mesh.NbrTet
    tet = mesh.Tet(n, :);
    V = mesh.Vertex(tet, :);
    poly = tetPlanePoly(V, axis, z0, tol);
    if isempty(poly)
        continue;
    end
    localVals = zeros(size(poly, 1), 1);
    for p = 1:size(poly, 1)
        localVals(p) = interpTetScalar(poly(p, :), tet, mesh.Vertex, field);
    end
    tris = polyToTris(size(poly, 1));
    for t = 1:size(tris, 1)
        idx = tris(t, :) + nodeCount;
        elems = [elems; idx]; %#ok<AGROW>
        xs = [xs; poly(tris(t, :), ia)]; %#ok<AGROW>
        ys = [ys; poly(tris(t, :), ib)]; %#ok<AGROW>
        vals = [vals; localVals(tris(t, :))]; %#ok<AGROW>
        nodeCount = nodeCount + 3;
    end
end

slice.x = xs;
slice.y = ys;
slice.val = vals;
slice.elem = elems;
slice.planeAxes = [ia, ib];
slice.z0 = z0;
end

function poly = tetPlanePoly(V, axis, coord, tol)
c = V(:, axis);
if coord < min(c) - tol || coord > max(c) + tol
    poly = [];
    return;
end

if all(abs(c - coord) < 1e-6)
    idx = find(abs(c - coord) < 1e-6);
    if numel(idx) >= 3
        poly = V(idx(1:3), :);
    else
        poly = [];
    end
    return;
end

edges = [1 2; 1 3; 1 4; 2 3; 2 4; 3 4];
pts = [];
for e = 1:size(edges, 1)
    a = edges(e, 1);
    b = edges(e, 2);
    ca = c(a);
    cb = c(b);
    if abs(ca - coord) < tol
        pts = [pts; V(a, :)]; %#ok<AGROW>
    elseif abs(cb - coord) < tol
        pts = [pts; V(b, :)]; %#ok<AGROW>
    elseif (ca - coord) * (cb - coord) < 0
        t = (coord - ca) / (cb - ca);
        pts = [pts; V(a, :) + t * (V(b, :) - V(a, :))]; %#ok<AGROW>
    end
end

if size(pts, 1) < 3
    poly = [];
    return;
end

uniq = pts(1, :);
for i = 2:size(pts, 1)
    d = sqrt(sum((pts(i, :) - uniq).^2, 2));
    if all(d > 1e-8)
        uniq = [uniq; pts(i, :)]; %#ok<AGROW>
    end
end
if size(uniq, 1) < 3
    poly = [];
elseif size(uniq, 1) > 4
    poly = uniq(1:4, :);
else
    poly = uniq;
end
end

function tris = polyToTris(n)
if n == 3
    tris = [1 2 3];
elseif n == 4
    tris = [1 2 3; 1 3 4];
else
    tris = [];
end
end

function val = interpTetScalar(p, tet, Vertex, field)
V = Vertex(tet, :);
f = field(tet);
A = [V(2, :) - V(1, :); V(3, :) - V(1, :); V(4, :) - V(1, :)]';
w123 = A \ (p(:) - V(1, :)');
w0 = 1 - sum(w123);
w = [w0; w123(:)];
val = sum(w .* f(:));
end
