\chapter{Practical guidance}
\label{ch:practical}

\section{Choosing sample counts}

The most common practical adjustment in this package is the choice of sample
counts. A curve with \verb|usamples=8| may be sufficient to establish the
shape of an arc, while a surface that is meant to carry lighting cleanly may
need a denser tessellation. There is no universal rule, but there is a useful
discipline: start with the coarsest tessellation that communicates the shape,
then increase counts only where the figure demands it.

That advice matters because more samples mean more simplices, and more
simplices mean more work for partitioning, filtering, and occlusion sorting.
Solids are especially expensive because three sample directions affect the
boundary tessellation.

\section{Writing source that remains readable}

The package rewards a style of source code in which repeated objects are named,
transformations are factored out, and filters are short enough to be read as
mathematical statements. In practical terms, this usually means using
\verb|\setobject| for recurring matrices or vectors, keeping draw and fill
styles consistent within a figure, and separating logically distinct scene
elements into their own append commands.

It is also wise to keep the final call to \verb|\displaysimplices| visibly
separate from the scene construction above it. That single line is the moment
at which the scene is committed to the page.

\section{Troubleshooting a figure}

When a figure behaves unexpectedly, four checks usually resolve the issue.

\begin{description}
	\item[Bracing] Make sure that Lua expressions containing commas are
	    wrapped in braces.
	\item[Sample counts] Check that \verb|usamples|, \verb|vsamples|, and
	    \verb|wsamples| are at least~2 where required.
	\item[Transformation order] Re-read composed matrices from left to right
	    in the order applied to points.  See
	    Appendix~\ref{ch:linalg} for the composition convention.
	\item[Filter semantics] Remember that filters act on tessellated
	    simplices, not on symbolic objects.
\end{description}

Two further behaviors are worth remembering because they can initially look
like errors.  Labels are drawn after the geometry, and lights are cleared
after each display call.  Both behaviors are intentional.

\section{Illustration program for the manual}

Since this document is intended to become an illustrated manual, the figures
should do more than decorate the text. Each figure ought to settle a specific
question in the reader's mind. The most useful illustrations are therefore not
merely attractive scenes, but comparisons and decompositions: before-and-after
occlusion, coarse versus fine tessellation, filtered versus unfiltered
geometry, and the effect of changing the transformation order.

\begin{figure}[tbp]
    \centering
    \begin{tikzpicture}
        \setobject[
            name=view,
            object={Matrix.xrotation3(-pi/5):multiply(Matrix.zrotation3(pi/6))}
        ]
        \appendlight[v={return Vector:new{1,1,2,1}}]
        \appendsurface[
            ustart=-1.5, ustop=1.5, usamples=12,
            vstart=-1.5, vstop=1.5, vsamples=12,
            v={return Vector:new{u, v, 0.4*u, 1}},
            transformation={view},
            fill options={fill=blue!60!ltdtbrightness, draw=blue!30!black, very thin}
        ]
        \appendsurface[
            ustart=-1.5, ustop=1.5, usamples=12,
            vstart=-1.5, vstop=1.5, vsamples=12,
            v={return Vector:new{u, 0.4*v, v, 1}},
            transformation={view},
            fill options={fill=orange!60!ltdtbrightness, draw=orange!30!black, very thin}
        ]
        \displaysimplices
    \end{tikzpicture}
    \caption{Two intersecting tilted planes rendered with occlusion-aware
    sorting.  The package partitions the simplices where the surfaces cross
    and draws them in the correct depth order.  Without the pipeline, one
    surface would simply paint over the other.}
\end{figure}

\begin{figure}[tbp]
    \centering
    \begin{tikzpicture}
        \setobject[
            name=view,
            object={Matrix.xrotation3(-pi/5):multiply(Matrix.zrotation3(pi/6))}
        ]
        \appendlight[v={return Vector:new{1,1,2,1}}]
        \appendsurface[
            ustart=0, ustop=tau, usamples=6,
            vstart=0, vstop=pi, vsamples=4,
            v={return Vector:new{sin(v)*cos(u)-4, sin(v)*sin(u), cos(v), 1}},
            transformation={view},
            fill options={fill=ltdtbrightness, draw=black, thin}
        ]
        \appendsurface[
            ustart=0, ustop=tau, usamples=12,
            vstart=0, vstop=pi, vsamples=8,
            v={return Vector:new{sin(v)*cos(u), sin(v)*sin(u), cos(v), 1}},
            transformation={view},
            fill options={fill=ltdtbrightness, draw=black, very thin}
        ]
        \appendsurface[
            ustart=0, ustop=tau, usamples=24,
            vstart=0, vstop=pi, vsamples=16,
            v={return Vector:new{sin(v)*cos(u)+4, sin(v)*sin(u), cos(v), 1}},
            transformation={view},
            fill options={fill=ltdtbrightness, draw=black, ultra thin}
        ]
        \appendlabel[
            v={return Vector:new{-4,-1.8,0,1}},
            text={$6\times4$}
        ]
        \appendlabel[
            v={return Vector:new{0,-1.8,0,1}},
            text={$12\times8$}
        ]
        \appendlabel[
            v={return Vector:new{4,-1.8,0,1}},
            text={$24\times16$}
        ]
        \displaysimplices
    \end{tikzpicture}
    \caption{The same sphere at three sampling densities.  At~$6\times4$
    the shape is barely recognizable; at~$12\times8$ the sphere is clear
    but faceted; at~$24\times16$ the surface appears smooth.  Higher
    sample counts produce more simplices for partitioning and sorting,
    so the tradeoff is visual fidelity against compile time.}
\end{figure}

\begin{figure}[tbp]
    \centering
    \begin{tikzpicture}
        \setobject[
            name=view,
            object={Matrix.xrotation3(-pi/5):multiply(Matrix.zrotation3(pi/6))}
        ]
        \appendlight[v={return Vector:new{1,1,2,1}}]
        \appendsurface[
            ustart=-1, ustop=1, usamples=16,
            vstart=-1, vstop=1, vsamples=16,
            v={return Vector:new{2*u, 2*v, 1.2*exp(-2*(u*u+v*v)), 1}},
            transformation={view},
            fill options={fill=cyan!30!ltdtbrightness, draw=black, very thin}
        ]
        \appendcurve[
            ustart=0, ustop=tau, usamples=36,
            v={return Vector:new{0.7*cos(u), 0.7*sin(u), 1.2*exp(-2*0.49), 1}},
            transformation={view},
            draw options={thick, red, dashed}
        ]
        \appendpoint[
            v={return Vector:new{0,0,1.2,1}},
            transformation={view},
            fill options={fill=black}
        ]
        \appendlabel[
            v={return Vector:new{0.3,0.3,1.5,1}},
            transformation={view},
            text={peak}
        ]
        \appendlabel[
            v={return Vector:new{1.0,0.6,0.2,1}},
            transformation={view},
            text={level curve}
        ]
        \displaysimplices
    \end{tikzpicture}
    \caption{A Gaussian bump with a labelled peak and a dashed level
    curve.  Labels are emitted after the geometry and therefore appear
    as an annotation layer on top of the scene.}
\end{figure}

\begin{figure}[tbp]
    \centering
    \begin{tikzpicture}
        \setobject[
            name = {view},
            object = {Matrix.xrotation3(-pi/5):multiply(Matrix.zrotation3(pi/6))}
        ]
        \appendlight[v={return Vector:new{1, 1, 2, 1}}]
        \setobject[
            name = {viewinverse},
            object = {view:inverse()}
        ]
        % Sphere
        \appendsurface[
            ustart = {0}, ustop = {tau}, usamples = {20},
            vstart = {0}, vstop = {pi}, vsamples = {14},
            v = {return Vector:new{
                1.5*sin(v)*cos(u),
                1.5*sin(v)*sin(u),
                1.5*cos(v),
                1
            }},
            transformation = {view},
            fill options = {
                preaction = {fill=blue!20!ltdtbrightness},
                postaction = {draw=blue!30!black, line width=0.15pt,
                    line join=round}
            }
        ]
        % Intersecting disc
        \appendsurface[
            ustart = {-2}, ustop = {2}, usamples = {10},
            vstart = {-2}, vstop = {2}, vsamples = {10},
            v = {return Vector:new{u, v, 0.3*u + 0.2, 1}},
            transformation = {view},
            fill options = {
                preaction = {fill=orange!30!ltdtbrightness, fill opacity=0.65},
                postaction = {draw=orange!50!black, line width=0.2pt,
                    line join=round}
            },
            filter = {
                local M = A:hadd(B):hadd(C):hscale(1/3):multiply(viewinverse)
                return M[1]*M[1] + M[2]*M[2] <= 4.01
            }
        ]
        \displaysimplices
    \end{tikzpicture}
    \caption{A sphere intersected by a tilted disc.  The package
    partitions both the sphere and the disc where they cross, producing
    fragments that are drawn in the correct depth order.  The disc's
    filter clips it to a circular region, demonstrating how filtering and
    partitioning cooperate in a single scene.}
\end{figure}

\begin{figure}[tbp]
    \centering
    \begin{tikzpicture}
        \setobject[
            name = {T},
            object = {
                Matrix.zyzrotation3(pi/2, pi/3, 5.25*pi/6)
                    :multiply(Matrix.translate3(0, 0, -5))
            }
        ]
        \setobject[
            name = {Tinv},
            object = {T:inverse()}
        ]
        \appendlight[v={return Vector:new{1, 1, 1, 1}}]
        % Surface: z = u^4 + v^4 − 4uv + 1
        \appendsurface[
            ustart = {-2}, ustop = {2}, usamples = {20},
            vstart = {-2}, vstop = {2}, vsamples = {20},
            v = {return Vector:new{u, v, u^4 + v^4 - 4*u*v + 1, 1}},
            transformation = {T},
            fill options = {
                preaction = {fill=green, fill opacity=0.2},
                postaction = {draw=blue, ultra thin,
                    line join=round}
            },
            filter = {
                local a = A:multiply(Tinv)
                local b = B:multiply(Tinv)
                local c = C:multiply(Tinv)
                return abs(a[3]) < 2.01 and abs(b[3]) < 2.01
                   and abs(c[3]) < 2.01
                   and abs(a[2]) < 2.01 and abs(b[2]) < 2.01
                   and abs(c[2]) < 2.01
                   and abs(a[1]) < 2.01 and abs(b[1]) < 2.01
                   and abs(c[1]) < 2.01
            }
        ]
        % Wireframe box
        \appendsolid[
            ustart = {-2}, ustop = {2}, usamples = {2},
            vstart = {-2}, vstop = {2}, vsamples = {2},
            wstart = {-2}, wstop = {2}, wsamples = {2},
            v = {return Vector:new{u, v, w, 1}},
            transformation = {T},
            fill options = {
                preaction = {fill=none, fill opacity=0.5},
                postaction = {draw=none, ultra thin,
                    line join=round, line cap=round}
            }
        ]
        % Coordinate axes
        \appendcurve[
            ustart = {0}, ustop = {4}, usamples = {2},
            v = {return Vector:new{u, 0, 0, 1}},
            transformation = {T},
            arrow tip = {fill=black},
            draw options = {draw, ultra thin, line cap=round}
        ]
        \appendlabel[
            v = {return Vector:new{4.3, 0, 0, 1}},
            transformation = {T},
            text = {\(x\)}
        ]
        \appendcurve[
            ustart = {0}, ustop = {4}, usamples = {2},
            v = {return Vector:new{0, u, 0, 1}},
            transformation = {T},
            arrow tip = {fill=black},
            draw options = {draw, ultra thin, line cap=round}
        ]
        \appendlabel[
            v = {return Vector:new{0, 4.3, 0, 1}},
            transformation = {T},
            text = {\(y\)}
        ]
        \appendcurve[
            ustart = {0}, ustop = {4}, usamples = {2},
            v = {return Vector:new{0, 0, u, 1}},
            transformation = {T},
            arrow tip = {fill=black},
            draw options = {draw, ultra thin, line cap=round}
        ]
        \appendlabel[
            v = {return Vector:new{0, 0, 4.3, 1}},
            transformation = {T},
            text = {\(z\)}
        ]
        \displaysimplices
    \end{tikzpicture}
    \caption{The surface $z = u^4 + v^4 - 4uv + 1$ rendered inside a
    bounding box with labelled coordinate axes.  The filter clips the
    surface to the box by transforming each triangle's vertices back to
    the local frame and testing all three coordinates against the box
    limits.  Arrow-tipped curves serve as axes, and labels provide
    annotation.  This style of figure---a surface, a bounding volume,
    axes, and labels---is a common pattern for mathematics
    illustrations.}
\end{figure}