% Patch cnltx-doc class \AddToHook{class/scrartcl/after}{ \NewCommandCopy{\originalAfterPackage}{\AfterPackage} \RenewDocumentCommand{\AfterPackage}{t! m m}{ \IfBooleanTF{#1}{#3}{% \originalAfterPackage{#2}{#3} } } } \makeatother \typeout{*** Patch cnltx-doc} \documentclass[ babel-options={english}, load-preamble-, title=compact ]{cnltx-doc} \usepackage[oldstyle]{libertine} \usepackage[scaled=.81]{DejaVuSansMono} \usepackage{enumitem} % Since the cnltx class doesn't do examples with lualatex, % we can't include our package. % Thus, we use readprov to get file information. \usepackage{readprov} \ReadFileInfos{seatingchart.sty} \providecommand{\packagename}{seatingchart} \def\thepkg{\pkg*{\packagename}} \setcnltx{ name = seatingchart, package = \packagename, version = \UseVersionOf{\packagename.sty}, date = \UseDateOf{\packagename.sty}, title = The \pkg*{seatingchart} Package, info = Generation and visualization of seating plans, authors = {Matthias Werner[matthias.werner@informatik.tu-chemnitz.de]}, abstract={ This package allows for easy creation of seating charts, such as those required for examinations. Several automatic placement schemes are predefined, but custom, fine-grained seat assignments can also be specified. While the package was initially intended for internal use at Chemnitz University of Technology and contains predefined seating layouts for (some) of the rooms of TUC, on the one hand the room data can be easily expanded or replaced, and on the other hand rooms can also be created ad hoc. }, url =https://github.com/tuc-osg/seatingchart, build-title } \def\thepkg{\pkg*{\packagename}} \begin{document} \section{Introduction} To conduct exams, we occasionally require seating plans. Over time, we have accumulated several such plans in the form of TikZ-supported \LaTeX\ files. Depending on the number of students in an exam—and how high we assess the risk of attempted cheating—we apply different placement schemes, which requires adapting the files accordingly. Moreover, we are sometimes assigned new rooms for which no seating plans exist yet. This was the motivation for developing the \thepkg\ package. It \ldots \begin{itemize}%[itemsep=0pt] \item enables quick and easy creation of seating plans; \item separates seat layout from the placement scheme; \item offers a set of standard placement schemes; \item includes a number of predefined rooms with seat layouts; \item allows for \emph{ad hoc} creation of new rooms and placement schemes. \end{itemize} \section{Dependencies} The \thepkg\ package works only with Lua\LaTeX\ and requires a sufficiently modern \LaTeX\ version, at least from July 2022. It loads the following packages: \begin{itemize}%[nosep] \item \pkg{etoolbox} \item \pkg{luacode} \item \pkg{tikz} \end{itemize} These packages are available in all major \TeX\ distributions and themselves depend on other packages. In particular, \pkg*{tikz} loads the \pkg{xcolor} package, whose color definitions are also used by \thepkg. \section{Seat Layout} \label{sec:layout} The package is loaded as usual with \cs{usepackage}\oarg{options}\{\thepkg\} This allows the layout of the seats—i.e., their arrangement in the room— to be defined right away. Seat assignment is done later; see Section~\ref{sec:seat-assignment}. \subsection{Class Options} \label{sec:class-options} The use of the option \option{room} distinguishes between two fundamental use cases: \begin{options} \keyval{room}{Room} This option key should be used if the desired room is already predefined. \keyval{layout}{institution}\Default{tu-chemnitz} The data for the predefined rooms is read from \code{seatingchart-}\meta{institution}\code{.sc}. This key can be used if own predefined rooms have been declared, see Section~\ref{sec:new-rooms}. \end{options} If the room is not already known, it can also be created \emph{ad hoc}, whereas several key–value options are required to describe the layout: \begin{options} \keychoice{shape}{rectangle,arc}\Default{rectangle} Specifies whether the seating layout is rectangular (\choices{rectangle}) or curved (\choices{arc}).% \footnote{For example, room A10.316 at TU~Chemnitz uses an arc layout.} \keyval{rows}{number}\Default*!{}\vspace{-.3\baselineskip} \keyval{seats per row}{number}\Default!{} Defines the number of seat rows and seats per row. The maximum number must always be specified here. For incomplete rows, seats will be removed later, but no additional seats can be added that lie outside the originally defined layout area. \textbf{Note:} Aisles between blocks of seats must be counted here as seats as well. \end{options} If you specify \textbf{both} the \option*{room} key \textbf{and} one of the keys \option*{rows} or \option*{seats per row} in the class options, the result is undefined. A warning will be issued in that case.\medskip All further class options define the visual representation of the room layout. They can also be set later using \cs{scConfig}; see Section~\ref{sec:late-options}. \begin{options} \keybool{blackboard}\Default{false} Draws a blackboard. \keyval{seat distance}{distance}\Default{2pt} Distance between seats. This also determines the row spacing. If you want these two values to differ, you must use the following keys: \keyval{seat neighbor distance}{Distance}\Default*{2pt}\vspace{-.3\baselineskip} \keyval{row distance}{distance}\Default{2pt} \keychoice{rownumbers}{none,left,right,both}\Default{none} For rectangular layouts, defines whether to display row numbers on the left, right, or both sides. Counting starts at the front (blackboard side).\newline \emph{Note:} For arc-shaped layouts, this function is currently not implemented. \keyval{rownumber distance}{distance}\Default{2pt} Distance between the row number and the outermost seats, if \option*{rownumbers} is not \code{none}. \keyval{empty seat background color}{color}\Default*{lightgray!20}\vspace{-.3\baselineskip} \keyval{empty seat border color}{color}\Default*{lightgray}\vspace{-.3\baselineskip} \keyval{assigned seat background color}{color}\Default*{lightgray!30}\vspace{-.3\baselineskip} \keyval{assigned seat border color}{color}\Default{black} Defines background and border colors for empty or assigned seats. The syntax of color names follows the specification of the \pkg*{xcolor} package. If the seats should not be differentiated by color, the keys \keyval-{seat background color}{color}\Default*\vspace{-.3\baselineskip} \keyval-{seat border color}{color}\Default can also be used. \keyval{assigned seat label font}{font command}\Default*{\cs*{small}}\vspace{-.3\baselineskip} \keyval-{assigned seat label color}{color}\Default{black} Sets the size and color of the seat label. \end{options} \subsection{Late Option Selection} \label{sec:late-options} \begin{commands} \command{scConfig}This command can be used to set all keys mentioned in Section~\ref{sec:class-options}, except for \option{room}, \option{shape}, \option{rows}, and \option{seats per row}, outside of the \cs*{documentclass} options. \end{commands} \subsection{Modifying the Seat Layout} \label{sec:modify-layout} Often, not all seats are present in every row. This is already taken into account when specifying a predefined room, but it may still be necessary to remove individual seats — for instance, if a folding seat is broken. When creating a custom layout, such modifications are typically required. For this purpose, \pkg\ provides the following commands: \begin{commands} \command{scRemoveSeatAt}[\marg{row}\marg{seat number}] Removes seat \meta{seat number} in row \meta{row} from the layout. The values refer to the original layout and are unaffected by previously removed seats. If \meta{seat number} is negative, counting starts from the right. \command{scRemoveSeats}[\marg{list}] Removes all seats listed in the comma-separated \meta{list}, where each entry is of the form \code{\{\meta{row},\meta{seat number}\}}. As with \cs*{scRemoveSeatAt}, row and seat numbers refer to the original layout. In the following example, the first three seats on the left and the first seat on the right in the first row are removed: \vspace{-.3\baselineskip} \begin{example}[code-only] \scRemoveSeats{{1,1},{1,2},{1,3},{1,-1}} \end{example}\vspace{-1.3\baselineskip} \command{scSetAisle}[\Oarg{\meta{start row}-\meta{end row}}\marg{seat number}] Inserts an aisle at the position of \meta{seat number} through all rows. Use the optional argument if the aisle should not span all rows. For horizontal aisles (which split a seat block into front and back instead of left and right), please use \cs*{scRemoveSeats}. While this is also possible for vertical aisles, automatically generated seating schemes may treat aisles created via \cs*{scSetAisle} differently than those created with \cs*{scRemoveSeats}. \end{commands} \subsection{Output} \label{sec:drawing} \begin{commands} \command{scDrawSeating}[\Oarg{seat width=\meta{width}, seat height=\meta{height}}] Renders the seating plan. \thepkg\ attempts to calculate the seat dimensions so that the available space for the complete plan is fully utilized. Since this may not always meet all needs, the optional argument allows the width and height of the seats on the plan to be adjusted individually. \end{commands} The following example shows the code and the result for a simple seating layout with a central aisle and two missing seats in the first row. \begin{example}[compile,program=lualatex,pages=1,add-frame,code-sep=\bigskip,graphics={scale=.25}] \documentclass{article} \usepackage[shape=rectangle, rows = 9, seats per row=15]{seatingchart} \begin{document} \scSetAisle{8} \scRemoveSeats{{1,1},{1,2}} \scDrawSeating \end{document} \end{example} \section{Seat Assignment} \label{sec:seat-assignment} \subsection{Parameters for Constructing Assignment Schemes} \label{sec:constr-scheme} A seating plan is only partially useful without indicating which seats are occupied. In \thepkg, seat assignment is handled via assignment schemes. To define such a scheme, the command \begin{commands} \command{scSeatingScheme}[\oarg{key list}\marg{name}] \vspace{-1.7\baselineskip} \command{scSeatingScheme}[\sarg\oarg{key list}\marg{pattern}] The mandatory argument, in the standard version of the command, is a name for a predefined seating scheme (see Section~\ref{sec:defined-schemes}). In the starred version, a string of "`\code{X}"’ and "`\code{-}"’ is passed, describing (the beginning of) a row assignment pattern, where "`\code{X}"’ denotes an occupied seat and "`\code{-}"’ an empty one. If the string is shorter than the number of seats in a row, it will be repeated. For example, \begin{example}[code-only]\vspace{-1.3\baselineskip} \scSeatingScheme*{X--} \end{example}\vspace{-1.3\baselineskip} marks every third seat as occupied. The optional argument accepts a list of key–value pairs that control the remaining settings of the assignment scheme. These are especially important in the starred variant but may also be used in the standard one. \begin{options} \keyval-{row sep}{number}\Default{2} Specifies how many rows should lie between two occupied rows. \keyval-{start row}{row} First row to be included in the assignment. \keyval-{end row}{row} Last row to be included in the assignment. \keyval-{row restart after}{number}\Default Resets the seat pattern after \meta{number} rows. This allows for alternating row spacing; see the example in Section~\ref{sec:ex:own1}. \keyval-{aisle counts}{number}\Default{1} Specifies how many seats wide an aisle should be considered. This allows for wider aisles to be taken into account. \keybool{aisle restarts scheme}\Default{false} Restarts the scheme after an aisle. In that case, the \option*{aisle counts} key has no effect. \keybool{ignore aisle}\Default*{false}\vspace{-.3\baselineskip} \keybool{ignore removed seats}\Default{false} When determining seat numbers (used e.g. in labels; see Section~\ref{sec:seat-label}), aisles and removed seats are normally counted. This ensures that seat numbers are consistent across rows (in rectangular layouts). If one of these keys is set, aisles or removed seats are no longer counted. This is particularly useful in curved layouts. \keyval{assigned seat label}{format string}\Default{m{{\,}}D} Specifies how assigned seats should be labeled. By default, this consists of the row number, a thin space, and a letter for the current occupied seat (e.g., "`3\,c"'). A number of other formats can be configured; see Section~\ref{sec:seat-label} for details. \end{options} \command{scConfigScheme\marg{key list}} Sets keys just like the optional argument of \cs*{scSeatingScheme}, but does not assign seats. \end{commands} Key values set by \cs*{scSeatingScheme} or \cs*{scConfigScheme} remain in effect until they are explicitly redefined. \subsection{Predefined Seating Schemes} \label{sec:defined-schemes} The \thepkg\ package defines a set of predefined seating schemes. Some of them also have alternative names. \begin{options} \opt{1x1} Every seat is marked.\newline Alternative name: \option{all} \opt{2x2} One empty seat and one empty row between two occupied ones.\newline Alternative name: \option{simple} \opt{2x2-} One empty seat between two occupied ones. After a single empty row, \emph{two} rows with occupied seats follow. This scheme allows the largest number of students in a room during an exam while still maintaining minimal lateral distance and enabling supervision to reach every student (from the front or the back).\newline Alternative name: \option{dense} \opt{2x3} Occupied seats have two empty seats between them laterally, and one empty row between occupied rows. This is considered the preferred default scheme for exams in our group.\newline Alternative name: \option{sixpack} \opt{2x3-} Rows are occupied as in \option{2x2-}, but the lateral spacing within an occupied row is two seats. \opt{2x4} Occupied seats have three empty seats between them laterally, and one empty row between occupied rows. \opt{3x4} Occupied seats have three empty seats between them laterally, and two empty rows between occupied rows. \end{options} \subsection{Seat Labeling} \label{sec:seat-label} The labeling of assigned seats can be done in various ways, controlled by assigning a format string to the key \option{assigned seat label}. Four counters are available for this purpose: \begin{itemize} \item absolute row: the row number in the seat layout \item occupied row: the number of the \emph{assigned} row. Rows without any assigned seats are skipped. \item absolute seat number: the seat number in the seat layout. Whether removed seats are counted depends on the value of \option*{ignore removed seats}. \item occupied seat number: the number of the \emph{assigned} seats. Unassigned seats are skipped in this count. \end{itemize} Each of these counters can be formatted differently. For this, the format string uses format specifiers listed in the following table:\medskip \begin{tabular}{llccccc}\hline \textbf{\sffamily Counter}&\textbf{\sffamily Description}&\multicolumn{5}{c}{\textbf{\sffamily Rendered as\ldots}}\\ &&\rotatebox{90}{Arabic numeral}&\rotatebox{90}{lowercase letter}&\rotatebox{90}{uppercase letter}& \rotatebox{90}{lower Roman numeral}&\rotatebox{90}{upper Roman numeral}\\\hline absolute row&\emph{based on seat layout}&\code{m}&\code{a}&\code{A}&\code{y}&\code{Y}\\ occupied row&\emph{based on assigned rows}&\code{r}&\code{b}&\code{B}&\code{i}&\code{I}\\ absolute seat number&\emph{based on seat layout}&\code{n}&\code{c}&\code{C}&\code{x}&\code{X}\\ occupied seat number&\emph{based on assigned seats}&\code{s}&\code{d}&\code{D}&\code{j}&\code{J}\\\hline \end{tabular}\medskip \noindent Parts of the label that should not be interpreted as format specifiers must be wrapped in double braces: \code{\{\{\meta{protected string}\}\}}. For example,\vspace{-1.3\baselineskip} \begin{example}[code-only] \scSeatingScheme[assigned seat label=Y{{-}}D]{2x3} \end{example}\vspace{-1.3\baselineskip} produces the label "`III-B"' for the fourth seat (from the left) in the third row. \subsection{Seat List} \label{sec:seats-list} Especially in the context of examinations, it is useful to generate a seat list, i.e., a tabular mapping between student and assigned seat. In its current version, \thepkg\ does not create a \LaTeX\ table, but it can support table generation (e.g., using \LaTeX\ or a spreadsheet application). \begin{commands} \command{scSeatingList}[\oarg{input file}\marg{output file}]\vspace{-1.3\baselineskip} \command{scSeatingList}[\sarg\oarg{input file}\marg{output file}] Creates a CSV file \meta{output file} containing the labels of the assigned seats, one per line.\medskip \framebox{\parbox{\linewidth}{ \textbf{Note!} The label texts written to \meta{output file} are extracted from the corresponding \LaTeX\ boxes, and only printable characters are included. When using this function, it's therefore recommended to avoid excessive \TeX-level formatting in the \option*{assigned seat label} format string. }}\medskip In the starred variant, each line is prefixed with the absolute coordinates (row, seat number, relative to the layout), comma-separated, before the label. If an input file is specified, its content is prepended line-by-line to the generated lines. For example, the input file could contain names and/or student IDs, which will then be matched to the assigned seats in the output. If there are fewer entries in \meta{input file} than assigned seats, the corresponding fields in the output will be left empty. If, on the other hand, there are more entries than available seats, \thepkg\ will report which entries could not be assigned a seat. \end{commands} \section{Examples} \label{sec:examples} To demonstrate the behavior of \thepkg, a few usage examples are documented here. \subsection{Dense Occupancy for Example Room in Section~\ref{sec:drawing}} \label{sec:ex-simple} \begin{example}[compile,program=lualatex,pages=1,add-frame,code-sep=\bigskip,graphics={scale=.25}] \documentclass{article} \usepackage[shape=rectangle, rows = 9, seats per row=15]{seatingchart} \begin{document} \scSetAisle{8} \scRemoveSeats{{1,1},{1,2}} \scSeatingScheme{2x2-} \scDrawSeating \end{document} \end{example} \subsection{Predefined Room, Rectangular} \label{sec:ex:std-rect} \begin{example}[compile,program=lualatex,pages=1,add-frame,code-sep=\bigskip,graphics={scale=.5}] \documentclass{scrartcl} % To make better use of the paper, we use landscape format % and reduce the margins \usepackage[a4paper,landscape,inner=10pt,outer=10pt,top=1cm,bottom=1cm]{geometry} \usepackage[ room=C10.115, blackboard ]{seatingchart} \begin{document} % Default title takes up too much space. \centering\textbf{\Huge\sffamily Seating Plan C10.115}\bigskip \scSeatingScheme{sixpack} \scDrawSeating \end{document} \end{example} \subsection{Predefined Room, Curved} \label{sec:ex:std-arc} \begin{example}[compile,program=lualatex,pages=1,add-frame,code-sep=\bigskip,graphics={scale=.5}] \documentclass{scrartcl} % To make better use of the paper, we use landscape format % and reduce the margins \usepackage[a4paper,landscape,inner=10pt,outer=10pt,top=1cm,bottom=1cm]{geometry} \usepackage[ room=A10.316, blackboard, assigned seat label color=blue ]{seatingchart} \begin{document} % Default title takes up too much space. \centering\textbf{\Huge\sffamily Seating Plan A10.316}\bigskip \scSeatingScheme[ignore removed seats]{2x2} \scDrawSeating \end{document} \end{example} \subsection{Custom Layout and Seating Scheme} \label{sec:ex:own1} \begin{example}[compile,program=lualatex,pages=1,add-frame,code-sep=\bigskip,graphics={scale=.5}] \documentclass{scrartcl} % To make better use of the paper, we use landscape format % and reduce the margins \usepackage[a4paper,landscape,inner=10pt,outer=10pt,top=1cm,bottom=1cm]{geometry} \usepackage[ shape=rectangle, rows=9, seats per row=9, assigned seat background color=yellow ]{seatingchart} \begin{document} \scRemoveSeats{{1,1},{1,-1},{2,1},{2,-1},{3,1},{3,-1}} \scSeatingScheme[ignore removed seats,end row=3]{2x3} \scSeatingScheme[start row=5, end row=10]{2x4} \scDrawSeating \end{document} \end{example} \subsection{Checkers} \label{sec:ex:dame} \begin{example}[compile,program=lualatex,pages=1,add-frame,code-sep=\bigskip,graphics={scale=.5}] \documentclass{scrartcl} \usepackage[a5paper,landscape,top=1cm,bottom=1cm]{geometry} \usepackage[shape=rectangle, rows=10,seats per row=10, assigned seat label color=blue, assigned seat background color=teal, empty seat background color=lime!50, seat distance=0pt]{seatingchart} \usepackage{stix} \begin{document} \centering\textbf{\Huge\sffamily Let's play Checkers}\bigskip \scConfigScheme{assigned seat label={}} \scSeatingScheme*[start row=5, end row=5]{X-} \scSeatingScheme*[start row=6, end row=6]{-X} \scConfigScheme{assigned seat label font=\Huge, assigned seat label={{{\textcolor{white}{$\circledbullet$}}}}} \scSeatingScheme*[start row=1, end row=3,row sep=2]{X-} \scSeatingScheme*[start row=2, end row=4]{-X} \scConfigScheme{assigned seat label={{{\textcolor{yellow}{$\circledbullet$}}}}} \scSeatingScheme*[start row=7, end row=9]{X-} \scSeatingScheme*[start row=8, end row=10]{-X} \scDrawSeating[seat width=1cm, seat height=1cm] \end{document} \end{example} \section{Declaration of New Rooms} \label{sec:new-rooms} In its current version, the \thepkg package only contains a relatively small number of rooms at TU Chemnitz with their seating layouts. Users will therefore often have to create their own layouts. In addition to the option for ad-hoc layout creation, as described in the se ction~\ref{sec:layout}, it is also possible to extend the package itself and create layouts for new rooms, which can then be easily accessed via the \option{room} key. For this purpose, custom \code{seatingchart-*.sc} files can be created and integrated via the \option{layout}. Two commands can be used in \code{seatingchart-*.sc} files: \begin{commands} \command{scDeclareRoom}[\marg{room name}\marg{key list}] A new room layout is created for the room \meta{room name}. The key list \emph{must} contain the three keys \begin{options} \keychoice{shape}{rectangle,arc}\Default*!{}%\vspace{-.3\baselineskip} \keyval-{rows}{number of rows}\Default*!{}%\vspace{-.3\baselineskip} and \keyval-{seats per row}{seats per row}\Default!{} These keys have the same meaning as the keys of the same name from Section~\ref{sec:layout}. This information about the base layout \emph{must} be followed by the key \opt{init}\Default! The layout can then be adjusted using \keyval-{aisle}{seat number}\vspace{-1.3\baselineskip} \keyval{remove}{list} These two keys function analogously to \cs*{scSetAisle} and \cs*{scRemoveSeats}, see Section~\ref{sec:modify-layout}. \end{options} \begin{example}[code-only] \scDeclareRoom{C10.115}{ shape=rectangle, rows=21, seats per row=35, init, aisle=18, remove={{1,1},{1,2},{1,3},{1,4},{1,-1},{1,-2},{1,-3},{1,-4}} } \end{example}\vspace{-1.3\baselineskip} \command{scAliasRoom}[\marg{alias}\marg{room}] Sets \meta{alias} as a replacement name for \meta{room}. \end{commands} If you would like your institution's layout file to be included in the package on CTAN, please send your file to the maintainer or initiate a pull request on \url{https://github.com/tuc-osg/seatingchart}. In this case, give the file a meaningful and distinguishable name. For example, \emph{University of Lummerland at Lummerland City} should use \code{seatingchart-lummerland-uni-lc.sc} rather than \code{seatingchart-lu.sc}. \section{Limitations and Bugs} \label{sec:bugs} Even though the \thepkg package is in practical use, at least in our group, it should be considered experimental. The \code{0} in the major version number indicates this fact. In particular, it means that the API is still subject to change. The package is subject to some limitations. Whether these will be fixed in future versions is not yet known. The package is designed for creating separate seating charts and therefore cannot be used to display multiple seating charts in one document. Likewise, seating layouts with staggered rows cannot be displayed. The number of predefined rooms is currently relatively small. There are plans to include additional rooms at TU Chemnitz in future patches. Layout files from other institutions are welcome. Curved room layouts are problematic for smaller row lengths. Please use GitHub for bug reports or pull requests: \url{https://github.com/tuc-osg/seatingchart}. \section{License} Permission is granted to copy, distribute and/or modify this software under the terms of the \LaTeX\ Project Public License (LPPL), version 1.3c or later (\url{http://www.latex-project.org/lppl.txt}). \end{document}