Skip to content

Instantly share code, notes, and snippets.

@sharadhr
Created January 18, 2022 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sharadhr/270f66664fa6a083fd0d20b9b23268d7 to your computer and use it in GitHub Desktop.
Save sharadhr/270f66664fa6a083fd0d20b9b23268d7 to your computer and use it in GitHub Desktop.
% epreport.cls simplifies typesetting experimental physics reports, and assignments.
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{epreport}[21/01/16 NUS Experimental Physics report document class]
%%%%% MISCELLANEOUS BUT PRIMARY IMPORTS %%%%%
\RequirePackage{iftex,etoolbox,expl3,xparse,silence}
% Import early to avoid option errors
\RequirePackage[table,dvipsnames,x11names]{xcolor}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% CLASS OPTIONS DECLARATION AND PROCESSING %%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% FONTS %%%%%
\newtoggle{islmodern}
\newtoggle{ismpro}
\toggletrue{islmodern}
\DeclareOption{lmodern}{}
\DeclareOption{minionpro}{\toggletrue{ismpro}\togglefalse{islmodern}}
%%%%% ARTICLE, REPORT, OR EXAM %%%%%
\providerobustcmd{\@classtype}{article}
\DeclareOption{article}{\renewrobustcmd{\@classtype}{article}}
\DeclareOption{report}{\renewrobustcmd{\@classtype}{report}}
\DeclareOption{exam}{\renewrobustcmd{\@classtype}{exam}}
%%%%% OTHER OPTIONS %%%%%
\newtoggle{hastikzlibs}
\newtoggle{hasdate}
\newtoggle{hasbib}
\newtoggle{apabib}
\newtoggle{ieeebib}
\DeclareOption{tikzlibs}{\toggletrue{hastikzlibs}}
\DeclareOption{date}{\toggletrue{hasdate}}
\DeclareOption{bibtex}{\toggletrue{hasbib}}
\DeclareOption{apabib}{\toggletrue{apabib}}
\DeclareOption{ieeebib}{\toggletrue{ieeebib}}
%%%%% PROCESS THE OPTIONS %%%%%
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{\@classtype}}
\ProcessOptions\relax
%%%%% LOAD THE APPROPRIATE CLASS AS A BASE %%%%%
\LoadClass{\@classtype}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FONT LOADING %%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\iftoggle{islmodern}{
\RequirePackage[T1]{fontenc}
\RequirePackage[utf8]{inputenc}
\RequirePackage{mlmodern}
\RequirePackage{amsmath, amsfonts, amssymb}
% \pdfmapfile{=mlm-substitute.map}
%%%%% Define tabular-lining as nothing
\providerobustcmd{\tablining}{\relax}
\RequirePackage{esint}
\RequirePackage[verbose=silent]{microtype}
}{}
\iftoggle{ismpro}{
\ifbool{pdftex}{
\RequirePackage[utf8]{inputenc}
\PassOptionsToPackage{verbose=silent}{microtype}
\RequirePackage[
onlytext,
lf,
swash,
loosequotes,
opticals,
footnotefigures
]{MinionPro}
\RequirePackage[withamsmath]{minionmath}
\RequirePackage{amsmath,amsfonts,amssymb}
\RequirePackage{minionamsmath}
%%%%% Define tabular-lining figures
\providerobustcmd{\tablining}{\figureversion{tab,lf}}
\renewcommand{\ttdefault}{lmtt}
% Use Minion Pro's swash script for \mathcal
\DeclareMathAlphabet\mathcal{T1}{\Mn@Math@Family}{m}{sw}
\SetMathAlphabet\mathcal{bold}{T1}{\Mn@Math@Family}{eb}{sw}
% Silence \arc redefined warning from pict2e
\WarningFilter*{pict2e}{\protect\arc\space redefined}
}{}
\ifboolexpr{bool{xetex} or bool{luatex}}{
\RequirePackage{fontspec}
\RequirePackage[math-style=ISO,bold-style=ISO,warnings-off={mathtools-colon,mathtools-overbracket}]{unicode-math}
\setmathfont[
Script = Math,
SizeFeatures = {
{Size=-6,Font=MinionMath-Tiny,Style=MathScriptScript},
{Size=6-8.4,Font=MinionMath-Capt,Style=MathScript},
{Size=8.4-,Font=MinionMath-Regular},
},
]{MinionMath-Regular}
\setmathfont[range=cal,Contextuals=Swash]{MinionPro-It}
\setmathfont[range=frak]{Latin Modern Math}
\setmathfont[range=scr]{Latin Modern Math}
\setmainfont[
UprightFeatures={
SizeFeatures={
{Size={-8.4},Font=MinionPro-Capt},
{Size={8.4-13},Font=MinionPro-Regular},
{Size={13-19.9},Font=MinionPro-Subh},
{Size={19.9-},Font=MinionPro-Disp}
},
{RawFeature = {protrusion = mnr}},
},
BoldFeatures={
SizeFeatures={
{Size={-8.4},Font=MinionPro-BoldCapt},
{Size={8.4-13},Font=MinionPro-Bold},
{Size={13-19.9},Font=MinionPro-BoldSubh},
{Size={19.9-},Font=MinionPro-BoldDisp}
},
{RawFeature = {protrusion=mnrb}},
},
ItalicFeatures={
SizeFeatures={
{Size={-8.4},Font=MinionPro-ItCapt},
{Size={8.4-13},Font=MinionPro-It},
{Size={13-19.9},Font=MinionPro-ItSubh},
{Size={19.9-},Font=MinionPro-ItDisp}
},
{RawFeature = {protrusion=mni}},
},
BoldItalicFeatures={
SizeFeatures={
{Size={-8.4},Font=MinionPro-BoldItCapt},
{Size={8.4-13},Font=MinionPro-BoldIt},
{Size={13-19.9},Font=MinionPro-BoldItSubh},
{Size={19.9-},Font=MinionPro-BoldItDisp}
},
{RawFeature = {protrusion=mnib}}
},
RawFeature= {expansion=default},
]{Minion Pro}
% TODO: More detailed Xe/LuaTeX code
}{}
}{}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% PACKAGE IMPORTS %%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% FONTS & SYMBOLS %%%%%
\RequirePackage[nointegrals]{wasysym}
% Silence font shape warning from wasysym
\WarningFilter{latexfont}{Font shape}
%%%%% GEOMETRY, PAGE SETUP, SPACING, PARAGRAPHING %%%%%
\RequirePackage[margin=2.5cm,a4paper]{geometry}
\RequirePackage{titlesec}
\RequirePackage{appendix}
\RequirePackage{multicol}
\RequirePackage{multirow}
\RequirePackage{parskip}
\RequirePackage{tabto}
\RequirePackage{pdflscape}
\RequirePackage{enumitem}
\RequirePackage{adjustbox}
\RequirePackage[super]{nth}
%%%%% SCIENCE FORMATTING AND LANGUAGE %%%%%
\RequirePackage{mathtools}
\RequirePackage{physics}
\RequirePackage[
arc-separator = \,,
retain-explicit-plus,
detect-weight=true,
detect-family=true,
detect-mode=true,
range-phrase=--,
range-units=single
]{siunitx}
\RequirePackage[version=4]{mhchem}
\RequirePackage[makeroom]{cancel}
\RequirePackage[british]{babel}
\RequirePackage{csquotes}
\RequirePackage[acronym]{glossaries}
% OPTIONS SETUP
\renewrobustcmd{\CancelColor}{\color{red}}
\renewrobustcmd{\emph}[1]{\textsl{#1}}
%%%%% GRAPHICS, CAPTIONS, TABLES %%%%%
\RequirePackage{graphicx}
\RequirePackage{float}
\RequirePackage{tikz,tikz-3dplot}
\RequirePackage{nicematrix}
\RequirePackage{pgfplots}
\RequirePackage{pdfpages}
\RequirePackage[
width=0.6\textwidth,
labelfont={small,bf},
font={small}]{caption}
\RequirePackage{subcaption}
\RequirePackage{array}
\RequirePackage{tabularx}
\RequirePackage{booktabs}
\RequirePackage[outline]{contour}
\RequirePackage[l3]{csvsimple}
\RequirePackage[skins,theorems]{tcolorbox}
% TIKZ LIBRARIES
\iftoggle{hastikzlibs}{%
\usetikzlibrary{
arrows,
arrows.meta,
angles,
calc,
calligraphy,
decorations.pathreplacing,
decorations.markings,
decorations.text,
external,
positioning,
pgfplots.dateplot,
quotes,
shapes.multipart
}
% \tikzexternalize[prefix=figures/]
%%%%% RADIO BUTTONS %%%%%
\NewDocumentCommand\radiobutton{s}{
\begin{tikzpicture}
\pgfmathsetlengthmacro\radius{height("X")/2}
\draw[radius=\radius] circle;
\IfBooleanTF#1{\fill[radius=.6*\radius] circle;}{}
\end{tikzpicture}
}
%%%%% MID ARROW DECORATION %%%%%
\tikzset{->-/.style={postaction={decorate,decoration={
markings,
mark=at position #1 with {\arrow{Stealth}}
}}},
>=Stealth
}
}{}
%%%%% TIKZ CIRCLES %%%%%
\providerobustcmd*\circled[1]{
\begin{tikzpicture}[baseline=(char.base)]
\node[shape=circle, draw, minimum size=1.6em, inner sep=0pt] (char) {#1};
\end{tikzpicture}
}
\pgfplotsset{compat=newest}
\contourlength{1pt}
%%%%% DEFAULT CENTRED FLOATS %%%%%
\g@addto@macro\@floatboxreset{\centering}
\g@addto@macro\@subfloatboxreset{\centering}
% TCOLORBOX SETUP
\tcbset{
shield externalize,
highlight math style={
enhanced,
colframe=red,
colback=white,
arc=0pt,
boxrule=1pt
}
}
\renewrobustcmd{\tabularxcolumn}[1]{m{#1}}
%%%%% REFERENCES AND LINKS %%%%%
\RequirePackage{hyperref}
\RequirePackage[noabbrev,capitalize]{cleveref}
\RequirePackage{appendix}
%%%%% MISCELLANEOUS %%%%%
\RequirePackage[en-GB,showdow,calc]{datetime2}
\DTMlangsetup[en-GB]{ord=raise}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% MATHS MACROS AND SIUNITX SETUP %%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\renewrobustcmd{\earth}{\oplus}
\DeclareSIUnit{\year}{y}
\DeclareSIUnit{\AU}{AU}
\DeclareSIUnit{\parsec}{pc}
\DeclareSIUnit{\lightyear}{ly}
\DeclareSIUnit{\earthmass}{\textit{M}_{\earth}}
\DeclareSIUnit{\jupitermass}{\textit{M}_{J}}
\DeclareSIUnit{\solarmass}{\textit{M}_{\astrosun}}
\DeclareSIUnit{\atm}{atm}
\providerobustcmd{\im}{\mkern0.5mu\mathrm{i}\mkern0.5mu}
\providerobustcmd{\e}{\mkern0.5mu\mathrm{e}\mkern0.5mu}
\providerobustcmd{\reals}{\mathbb{R}}
\providerobustcmd{\naturals}{\mathbb{N}}
\providerobustcmd{\integers}{\mathbb{Z}}
\providerobustcmd{\rationals}{\mathbb{Q}}
\providerobustcmd{\complexes}{\mathbb{C}}
\providerobustcmd{\tomb}{\quad\blacksquare{}}
\providerobustcmd*{\ra}[2][]{%
\ang[
math-degree=\textsuperscript{h},
text-degree=\textsuperscript{h},
math-arcminute=\textsuperscript{m},
text-arcminute=\textsuperscript{m},
math-arcsecond=\textsuperscript{s},
text-arcsecond=\textsuperscript{s},
#1]{#2}%
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% CLEVEREF AND HYPERREF SETUP %%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\crefdefaultlabelformat{#2\textbf{#1}#3}
\creflabelformat{equation}{#2\textbf{(#1)}#3}
\creflabelformat{figure}{#2\textbf{#1}#3}
\creflabelformat{table}{#2\textbf{#1}#3}
\crefname{equation}{\textbf{equation}}{\textbf{equations}}
\Crefname{equation}{\textbf{Equation}}{\textbf{Equations}}
\crefname{figure}{\textbf{Figure}}{\textbf{Figures}}
\Crefname{figure}{\textbf{Figure}}{\textbf{Figures}}
\crefname{table}{\textbf{Table}}{\textbf{Tables}}
\Crefname{table}{\textbf{Table}}{\textbf{Tables}}
\crefname{appendix}{\textbf{Appendix}}{\textbf{Appendices}}
\Crefname{appendix}{\textbf{Appendix}}{\textbf{Appendices}}
\crefname{section}{\textbf{\S}}{\textbf{\S}}
\Crefname{section}{\textbf{\S}}{\textbf{\S}}
\crefname{algorithm}{\textbf{Algorithm}}{\textbf{Algorithms}}
\Crefname{algorithm}{\textbf{Algorithm}}{\textbf{Algorithms}}
\hypersetup{
colorlinks = true, % Colours links instead of ugly boxes
urlcolor = magenta, % Colour for external hyperlinks
linkcolor = magenta, % Colour of internal links
citecolor = teal % Colour of citations
}
\AtBeginEnvironment{appendices}{\crefalias{section}{appendix}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% BIBLIOGRAPHY SETUP %%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\iftoggle{hasbib}{
\RequirePackage[nottoc,numbib]{tocbibind}
\iftoggle{ieeebib}{
\RequirePackage[
backend=biber,
language=british,
backref=true,
style=verbose-ieee,
bibstyle=numeric,
citestyle=numeric,
sorting=none,
]{biblatex}
\DefineBibliographyStrings{english}{%
backrefpage = {page},% originally "cited on page"
backrefpages = {pages},% originally "cited on pages"
}
\DeclareCiteCommand{\supercite}[\mkbibsuperscript]
{\iffieldundef{prenote}
{}
{\BibliographyWarning{Ignoring prenote argument}}%
\iffieldundef{postnote}
{}
{\BibliographyWarning{Ignoring postnote argument}}}
{\usebibmacro{citeindex}%
\bibopenbracket\usebibmacro{cite}\bibclosebracket}
{\supercitedelim}
{}
\let\cite=\supercite
}{}
\iftoggle{apabib}{
\RequirePackage[
backend=biber,
style=apa,
language=british,
]{biblatex}
}{}
\RequirePackage{biblatex}
}{}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% EXAM CLASS SETUP %%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\ifdefstring{\@classtype}{exam}{
%%%%% QUESTION/CHOICE LABELS %%%%%
\renewrobustcmd{\questionlabel}{\thequestion.\hfill}
\renewrobustcmd{\subpartlabel}{(\thesubpart)}
\renewrobustcmd{\choicelabel}{\circled{\thechoice}}
%%%%% POINTS FORMATTING %%%%%
\renewrobustcmd{\questionshook}{
\setlength{\rightpointsmargin}{1.75cm}
\setlength{\itemsep}{30pt}
}
%%%%% QUESTION/PART/SUBPART INDENTATION %%%%%
\renewrobustcmd{\partshook}{
\renewrobustcmd\makelabel[1]{\rlap{##1}\hss}
% \setlength{\itemsep}{6pt}
}
\renewrobustcmd{\subpartshook}{
\renewrobustcmd\makelabel[1]{\rlap{##1}\hss}
% \setlength{\itemsep}{6pt}
}
\renewrobustcmd{\subsubpartshook}{
\renewrobustcmd\makelabel[1]{\rlap{##1}\hss}
% \setlength{\itemsep}{6pt}
}
\renewrobustcmd{\choiceshook}{
\setlength{\labelsep}{10pt}
\settowidth{\leftmargin}{\circled{W}.\hspace{5pt}\hspace{0em}}
\setlength{\itemsep}{6pt}
}
\renewrobustcmd{\solutiontitle}{
\noindent\textbf{Solution:}\par\noindent
}
%%%%% MCQ STATEMENTS LIST AND COMMANDS %%%%%
\newlist{statements}{enumerate}{1}
\setlist[statements]{align=left,leftmargin=*,parsep=8pt,label=\textbf{\Roman{*}}.}
%%%%% MCQ STATEMENTS AND CHOICES ON ONE PAGE %%%%%
\BeforeBeginEnvironment{choices}{\par\nopagebreak\minipage{\linewidth}}
\AfterEndEnvironment{choices}{\endminipage}
\BeforeBeginEnvironment{statements}{\par\nopagebreak\minipage{\linewidth}}
\AfterEndEnvironment{statements}{\endminipage\vspace*{6pt}}
%%%%% ONEPAR CHOICES SPREAD %%%%%
\patchcmd{\oneparchoices}{\penalty -50\hskip 1em plus 1em\relax}{\hfill}{}{}
\patchcmd{\oneparchoices}{\penalty -50\hskip 1em plus 1em\relax}{\hfill}{}{}
%%%%% SOLUTION ENVIRONMENT %%%%%
\SolutionEmphasis{\color{blue}}
\correctchoiceemphasis{\color{blue}}
\marksnotpoints{}
\pointsinrightmargin{}
\pointsdroppedatright{}
\pointformat{\bfseries\textbf[\themarginpoints]}
%%%%% REDEFINE COVER PAGINATION AS ARABIC %%%%%
\renewenvironment{coverpages}{
\ifnum \value{numquestions}>0\relax
\ClassError{exam}{
Coverpages cannot be used after questions have begun.\MessageBreak
}{
All question, part, subpart, and subsubpart environments
\MessageBreak
must begin after the cover pages are complete.\MessageBreak
}
\fi
\@coverpagestrue
\adj@hdht@ftht
\thispagestyle{headandfoot}
}{
\clearpage
\@coverpagesfalse
\adj@hdht@ftht
}
\creflabelformat{question}{#2\textbf{#1}#3}
\creflabelformat{partno}{(#2\textbf{#1}#3)}
\creflabelformat{subpart}{(#2\textbf{#1}#3)}
\crefname{question}{question}{questions}
\Crefname{question}{Question}{Questions}
}{}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%%%%% MISCELLANEOUS %%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% SET NUMBERED AND BULLETED LIST MARGIN
\setlist[itemize, 1]{left=0pt}
\setlist[enumerate, 1]{left=0pt,label=\arabic*.}
%%%%% SET TABULAR FIGURES IN TABLES %%%%%
\AtBeginEnvironment{tabular}{
% \tablining
% \sisetup{text-rm={\tablining}}
}
%%%%% COPY-PASTABLE PDF %%%%%
\ifbool{pdftex}{
\input{glyphtounicode}
\pdfgentounicode=1
}{}
%%%%% MICROTYPE SETUP FOR HYPHENATION %%%%%
\pretolerance=2500
\tolerance=4500
\emergencystretch=0pt
\righthyphenmin=4
\lefthyphenmin=4
%%%%%% PROVIDE RELEVANT COMMANDS %%%%%
\newrobustcmd*{\@module}{}
\newrobustcmd*{\@matricno}{}
\providerobustcmd*{\module}[1]{\renewcommand\@module{\textbf{#1}}}
\providerobustcmd*{\matricno}[1]{\renewcommand\@matricno{\textbf{#1}}}
%%%%% CUSTOM TITLE %%%%%
\ifdefstring{\@classtype}{article}{
\renewrobustcmd{\@maketitle}[1]{
\newpage
\null
\begin{center}
\let \footnote \thanks
{\LARGE \@module \\ \@title \par}
\vskip 1.5em
{\large
\lineskip .5em
\ifdefstring{\@author}{\@latex@warning@no@line{No \noexpand\author given}}{
\par}{
\begin{tabular}[t]{c}
\@author \\
\@matricno
\end{tabular}\par}}
\iftoggle{hasdate}{\vskip 1em{\large \@date}}{}
\end{center}
\par
\vskip 1.5em
}
}{}
\ifdefstring{\@classtype}{exam}{
\renewrobustcmd{\@maketitle}[1]{
\newpage
\null
\begin{center}
\let \footnote \thanks
{\LARGE \@module \\ \@title \par}
\vskip 1.5em
{\large
\lineskip .5em
\ifdefstring{\@author}{\@latex@warning@no@line{No \noexpand\author given}}{
\par}{
\begin{tabular}[t]{c}
\@author \\
\@matricno
\end{tabular}\par}}
\iftoggle{hasdate}{\vskip 1em {\large \@date}}{}
\end{center}
\par
\vskip 1.5em
}
}{}
\ifdefstring{\@classtype}{report}{
\ifbool{@titlepage}{
\renewcommand\maketitle{
\begin{titlepage}%
\let\footnotesize\small
\let\footnoterule\relax
\let \footnote \thanks
\null\vfil
\vskip 60\p@
\begin{center}%
{\Huge \@module \\ \@title \par}%
\vskip 3em%
{\Large
\lineskip .75em%
\ifdefstring{\@author}{\@latex@warning@no@line{No \noexpand\author given}}{
\par}{
\begin{tabular}[t]{c}
\@author \\
\@matricno
\end{tabular}\par}}%
\iftoggle{hasdate}{\vskip 1.5em{\large \@date \par}
}{}
\end{center}\par
\@thanks
\vfil\null
\end{titlepage}%
\setcounter{footnote}{0}%
\global\let\thanks\relax
\global\let\maketitle\relax
\global\let\@thanks\@empty
\global\let\@author\@empty
\global\let\@date\@empty
\global\let\@title\@empty
\global\let\title\relax
\global\let\author\relax
\global\let\date\relax
\global\let\and\relax
}
}{
\renewrobustcmd{\@maketitle}[1]{
\newpage
\null
\begin{center}
\let \footnote \thanks
{\LARGE \@module \\ \@title \par}
\vskip 1.5em
{\Large
\lineskip .5em
\begin{tabular}[t]{c}
\@author \\
\@matricno
\end{tabular}\par}
\iftoggle{hasdate}{\vskip 1em {\large \@date}}{}
\end{center}
\par
\vskip 1.5em
}
}
}{}
% chktex-file 1
% chktex-file 36
% chktex-file 37
\documentclass[exam,answers,tikzlibs]{epreport}
\module{CS3241 Computer Graphics}
\title{AY2021/2022 Semester 1 Midterm Worked Solutions}
\date{5 October 2021}
\begin{document}
\maketitle
\begin{questions}
\setcounter{question}{5}
\question{
Given the \(R\), \(G\) and \(B\) colour values of a pixel, we would like to compute the perceived brightness of the pixel using the formula \(k_{R} \cdot R+ k_{G} \cdot G+ k_{B} \cdot B\), where a higher value corresponds to a higher brightness.
Which of the following are the most suitable values for constants \(k_{R}\), \(k_{G}\), and \(k_{B}\), respectively?
\begin{choices}
\choice \(k_{R} = 0.2\), \(k_{G} = 0.3\), \(k_{B} = 0.5\)
\choice \(k_{R} = 0.5\), \(k_{G} = 0.1\), \(k_{B} = 0.4\)
\choice \(k_{R} = 0.3\), \(k_{G} = 0.4\), \(k_{B} = 0.3\)
\choice \(k_{R} = 0.2\), \(k_{G} = 0.4\), \(k_{B} = 0.4\)
\correctchoice \(k_{R} = 0.3\), \(k_{G} = 0.6\), \(k_{B} = 0.1\)
\choice \(k_{R} = 0.1\), \(k_{G} = 0.6\), \(k_{B} = 0.3\)
\end{choices}
\begin{solution}
The luma function as defined by \href{https://en.wikipedia.org/wiki/Relative_luminance}{Rec. 709}, which converts an RGB triplet to a monochromatic brightness value, is given by
\begin{equation}
Y = 0.2126R + 0.7152G + 0.0722B
\end{equation}
\circled{E} is closest to the coefficients in this function.
The more important thing to note is that the human eye is far \emph{less} sensitive to blue light changes than red, and is \emph{most} sensitive to changes in intensity of green.
This was discussed in \href{https://luminus.nus.edu.sg/modules/4bb6b1c2-6146-420b-bf88-18ec9ad23dd3/files/f1d0bca8-1cd6-4c1e-b628-68ace9adf65c}{Tutorial 1}, questions 1 and 2.
By this property alone, it could be deduced that \circled{E} was the correct answer.
\end{solution}
}
\setcounter{question}{9}
\question{
Given that 3D vectors \(\vb*{u}\) and \(\vb*{v}\) are \textbf{unit vectors}, what is the value of their \textbf{dot product} (ie \(\vb*{u}\cdot\vb*{v}\)) when the angle between \(\vb*{u}\) and \(\vb*{v}\) is larger than a right angle and smaller than 180 degrees?
\begin{choices}
\choice 1
\choice 0
\choice \(\frac{\pi}{2}\)
\choice \(\frac{\pi}{4}\)
\correctchoice A value greater than \(-1\) and less than 0
\choice A value greater than 0 and less than 1
\choice The result is a 3D vector
\choice None of the other options is the correct answer
\end{choices}
\begin{solution}
Note that for vectors in \(\reals^{3}\), the dot product is defined as:
\begin{equation}
\vb*{u}\cdot\vb*{v} = \norm{\vb*{u}}\norm{\vb*{v}}\cos(\theta)
\end{equation} where \(\theta \) is the angle between \(\vb*{u}\) and \(\vb*{v}\), lying on the plane described by the two vectors.
Now, it is already given that the two vectors are unit vectors, ie \(\norm{\vb*{u}} = \norm{\vb*{v}} = 1\).
Furthermore, \(\cos(\theta) \in \bqty{-1, 0} : \theta \in \bqty{\frac{\pi}{2}, \frac{3\pi}{2}}\). Hence, \circled{E} is the answer.
\end{solution}
}
\setcounter{question}{14}
\question{
Suppose we want to position the camera at the world-space location \((e_{x}, e_{y}, e_{z})\), with the camera's view direction pointing in the \(y\)-direction, and the ``up-vector'' pointing in the direction \((1, 0, 1)\).
Which of the following \texttt{gluLookAt()} function calls achieves an equivalent view transformation?
\begin{choices}
\choice \texttt{gluLookAt(ex, ey, ez, 0, 1, 0, 1, 0, 1);}
\choice \texttt{gluLookAt(ex, ey, ez, 0, -1, 0, -1, 0, -1);}
\correctchoice \texttt{gluLookAt(ex, ey, ez, ex, ey+5, ez, 3, 1, 3);}
\choice \texttt{gluLookAt(ex, ey, ez, ex, ey-5, ez, -1, 1, -1);}
\choice \texttt{gluLookAt(ex, ey, ez, ex, ey+1, ez, -1, 0, -1 );}
\choice \texttt{gluLookAt(ex, ey, ez, ex, ey-1, ez, 1, 0, 1 );}
\choice None of the other options is the correct answer
\end{choices}
\begin{solution}
`The camera's view direction pointing in the \(y\)-direction' implies that \(\vb*{z}_{c}\) is \(\pqty{0, -1, 0}\) (taking negatives), ie \(\vb*{r}_{\text{eye}} - \vb*{r}_{\text{at}}\) = \(k\pqty{0, -1, 0}\).
Hence, by observation alone, we may eliminate options \circled{A}, \circled{B}, \circled{D}, and \circled{F}. For the remaining options, we can employ the cross-product to confirm the direction of the camera \(x\)-axis.
For the question:
\begin{align*}
\vb*{x}_{c} & = \norm{\vb*{z}_{c} \times \pmqty{1 & 0 & 1}^{\intercal}} \\
& = \norm{\pmqty{0 & 1 & 0} \times \pmqty{1 & 0 & 1}} \\
& = \norm{\pmqty{1 & 0 & 1}} = \pmqty{-\frac{1}{\sqrt{2}}, 0, \frac{1}{\sqrt{2}}}
\end{align*}
For \circled{C}:
\begin{align*}
\vb*{x}_{c} & = \norm{\vb*{z}_{c} \times \pmqty{3 & 1 & 3}^{\intercal}} \\
& = \norm{\pmqty{0 & -1 & 0}^{\intercal} \times \pmqty{3 & 1 & 3}^{\intercal}} \\
& = \norm{\pmqty{-3 & 0 & 3}} = \pmqty{-\frac{1}{\sqrt{2}}, 0, \frac{1}{\sqrt{2}}}
\end{align*}
Hence, the answer is \circled{C}.
We can also arrive at the answer by a more `hand-wavy' method of observation, by noticing that \(\pmqty{3 & 1 & 3}\) is more along the `same direction' as \(\pmqty{1 & 0 & 1}^{\intercal}\) than \(\pmqty{-1 & 0 & -1}^{\intercal}\) is (in fact, the latter is precisely \emph{opposite} to the required \(\vb*{k}_{\text{up}}\)) in the question.
\end{solution}
}
\question{
Consider the following OpenGL \texttt{glOrtho()} function call:
\begin{center}
\texttt{glOrtho(0, 10, 0, 20, 0, 100)}
\end{center}
Which of the following transformation matrices is the one produced by the \texttt{glOrtho()} function call?
Note that \(\vb*{T}\pqty{d_{x}, d_{y}, d_{z}}\) is a translation matrix for displacing a point by \(\pqty{d_{x}, d_{y}, d_{z}}\), and \(\vb*{S}\pqty{s_{x}, s_{y}, s_{z}}\) is a scaling matrix for scaling a point by factors of \(s_{x}\), \(s_{y}\), and \(s_{z}\) in the \(x\), \(y\), and \(z\) directions respectively.
\begin{choices}
\correctchoice \(\vb*{S}(2/10, 2/20, -2/100) \cdot \vb*{T}(-5, -10, 50)\)
\choice \(\vb*{S}(2/10, 2/20, -2/100) \cdot \vb*{T}(-5, -10, -50)\)
\choice \(\vb*{S}(2/10, 2/20, 2/100) \cdot \vb*{T}(-5, -10, 50)\)
\choice \(\vb*{S}(2/10, 2/20, 2/100) \cdot \vb*{T}(-5, -10, -50)\)
\choice \(\vb*{T}(-5, -10, 50) \cdot \vb*{S}(2/10, 2/20, -2/100)\)
\choice \(\vb*{T}(-5, -10, -50) \cdot \vb*{S}(2/10, 2/20, -2/100)\)
\end{choices}
\begin{solution}
From the lecture notes, \href{https://luminus.nus.edu.sg/modules/4bb6b1c2-6146-420b-bf88-18ec9ad23dd3/files/75ec8ac1-b346-47a2-ab6b-26d9dae2a261}{\texttt{T05\_camera\_viewing.pdf}}, the orthographic projection matrix,
\begin{equation}
\vb*{M}_{\text{ortho}} = \vb*{S}\pqty{\frac{2}{r - l}, \frac{2}{t - b}, \frac{2}{n - f}}\cdot\vb*{T}\pqty{\frac{-r - l}{2}, \frac{-t - b}{2}, \frac{f + n}{2}}
\end{equation}
Hence, substituting in the values, we find that \circled{A} is the correct answer.
\end{solution}
}
\question{
Suppose the viewport is set up with \texttt{glViewport(200, 100, 600, 400)}, and the entire viewport is within the rendering window.
What are the \textbf{2D window coordinates} and \textbf{depth value} of the NDC point \((0,0,0)\)?
\begin{choices}
\choice Window coordinates: \((400, 250)\), and depth: \(1.0\)
\choice Window coordinates: \((400, 250)\), and depth: \(0.0\)
\choice Window coordinates: \((400, 250)\), and depth: \(0.5\)
\choice Window coordinates: \((500, 300)\), and depth: \(1.0\)
\choice Window coordinates: \((500, 300)\), and depth: \(0.0\)
\correctchoice Window coordinates: \((500, 300)\), and depth: \(0.5\)
\end{choices}
\begin{solution}
\texttt{glViewport(x, y, w, h)} sets up the viewport transform from the NDC cube \(\bqty{-1, 1}^{3}\). The transforms for the \(x\)-, \(y\)-, and \(z\)-coordinates are:
\begin{align*}
x_{\text{w}} & = \pqty{x_{\text{NDC}} + 1}\pqty{\frac{w}{2}} + x \\
y_{\text{w}} & = \pqty{y_{\text{NDC}} + 1}\pqty{\frac{h}{2}} + y \\
z_{\text{w}} & = \frac{z_{\text{NDC}}+1}{2}
\end{align*}
Plugging the variables in the question into these equations gives \circled{F}.
\end{solution}
}
\setcounter{question}{18}
\begin{EnvFullwidth}
\vspace{20pt}
Consider the following application program code fragment:
\begin{center}
\begin{verbatim}
glMatrixMode(GL_MODELVIEW);
glLoadMatrixd(A);
glPushMatrix();
glMultMatrixd(B);
glBegin(GL_POINTS); glVertex3dv(v1); glEnd();
glMultMatrixd(C);
glLoadMatrixd(D);
glPushMatrix();
glMultMatrixd(E);
glMultMatrixd(F);
glBegin(GL_POINTS); glVertex3dv(v2); glEnd();
glLoadMatrixd(G);
glPopMatrix();
glMultMatrixd(H);
glBegin(GL_POINTS); glVertex3dv(v3); glEnd();
glPushMatrix();
glMultMatrixd(J);
glPushMatrix();
glMultMatrixd(K);
glBegin(GL_POINTS); glVertex3dv(v4); glEnd();
glPopMatrix();
glMultMatrixd(L);
glBegin(GL_POINTS); glVertex3dv(v5); glEnd();
glPopMatrix();
glPopMatrix();\end{verbatim}
\end{center}
\end{EnvFullwidth}
\question{
What are the actual transformations applied to the vertex \(\vb*{v}_{2}\)?
}
\begin{choices}
\choice \(\vb*{ABCDEFv}_{2}\)
\choice \(\vb*{FEDCBAv}_{2}\)
\choice \(\vb*{BCDEFv}_{2}\)
\choice \(\vb*{FEDCBv}_{2}\)
\choice \(\vb*{DEFCv}_{2}\vb*{G}\)
\correctchoice \(\vb*{DEFv}_{2}\)
\choice \(\vb*{FEDv}_{2}\)
\choice None of the other options is the correct answer
\end{choices}
\begin{solution}
For this question, we need to go line-by-line to determine the matrix at the \emph{top} of the \texttt{MODELVIEW} stack that is pre-multiplied to any vertex rendered to the display, with \texttt{glBegin(); glVertex(); glEnd()}.
Below, \texttt{LM(X)} is used as a substitute for \texttt{glLoadMatrixd(X)}, \texttt{MM(X)} is a substitute for \texttt{glMultMatrixd(X)}, \texttt{PuM} is used as a substitute for \texttt{glPushMatrix()}, \texttt{PoM} is used as a substitute for \texttt{glPopMatrix()}, and \texttt{V(x)} substitutes \texttt{glVertex(x)}.
\begin{center}
\begin{tikzpicture}[stack/.style={
draw,
node distance=1.6cm,
rectangle split,
rectangle split parts=#1,
rectangle split part fill={red!20,white}, anchor=south},
]
\node[stack=1,label=below:{\texttt{LM(A)}}] (LMA) {
\nodepart{one}\(\vb*{A}\)
};
\node[stack=2,label=below:{\texttt{PuM}},right=of LMA.south east, anchor=south west] (PUM1) {
\nodepart{one}\(\vb*{A}\)
\nodepart{two}\(\vb*{A}\)
};
\node[stack=2,label=below:{\texttt{MM(B)}},right=of PUM1] (MMB) {
\nodepart{one}\(\vb*{AB}\)
\nodepart{two}\(\vb*{A}\)
};
\draw[->,,right=of MMB.center] ($(MMB.one split east) + (0.8, 0)$) node[anchor=north] {\texttt{V(v1)}} -- +(0, 1.5) node[anchor=south] {\(\vb*{ABv}_{1}\)};
\node[stack=2,label=below:{\texttt{MM(C)}},right=of MMB] (MMC) {
\nodepart{one}\(\vb*{ABC}\)
\nodepart{two}\(\vb*{A}\)
};
\node[stack=2,label=below:{\texttt{LM(D)}},right=of MMC] (LMD) {
\nodepart{one}\(\vb*{D}\)
\nodepart{two}\(\vb*{A}\)
};
\node[stack=3,label=below:{\texttt{PuM}},right=of LMD.south east, anchor=south west] (PUM2) {
\nodepart{one}\(\vb*{D}\)
\nodepart{two}\(\vb*{D}\)
\nodepart{three}\(\vb*{A}\)
};
\node[stack=3,label=below:{\texttt{MM(E)}},below=2 cm of LMA] (MME) {
\nodepart{one}\(\vb*{DE}\)
\nodepart{two}\(\vb*{D}\)
\nodepart{three}\(\vb*{A}\)
};
\node[stack=3,label=below:{\texttt{MM(F)}},right=of MME] (MMF) {
\nodepart{one}\(\vb*{DEF}\)
\nodepart{two}\(\vb*{D}\)
\nodepart{three}\(\vb*{A}\)
};
\draw[->,,right=of MMF.center] ($(MMF.two split east) + (0.8, 0)$) node[anchor=north] {\texttt{V(v2)}} -- +(0, 1.5) node[anchor=south] {\(\vb*{DEFv}_{2}\)};
\node[stack=3,label=below:{\texttt{LM(G)}},right=of MMF](LMG) {
\nodepart{one}\(\vb*{G}\)
\nodepart{two}\(\vb*{D}\)
\nodepart{three}\(\vb*{A}\)
};
\node[stack=2,label=below:{\texttt{PoM}},right=of LMG.south east,anchor=south west] (POM1) {
\nodepart{one}\(\vb*{D}\)
\nodepart{two}\(\vb*{A}\)
};
\node[stack=2,label=below:{\texttt{MM(H)}},right=of POM1] (MMH) {
\nodepart{one}\(\vb*{DH}\)
\nodepart{two}\(\vb*{A}\)
};
\draw[->,,right=of MMH.center] ($(MMH.one split east) + (0.8, 0)$) node[anchor=north] {\texttt{V(v3)}} -- +(0, 1.5) node[anchor=south] {\(\vb*{DHv}_{3}\)};
\node[right=of MMH](dots) {\textbf{\dots}};
\end{tikzpicture}
\end{center}
\end{solution}
\question{
What are the transformations applied to the vertex \(\vb*{v}_{3}\)?
\begin{choices}
\correctchoice \(\vb*{DHv}_{3}\)
\choice \(\vb*{GHv}_{3}\)
\choice \(\vb*{GDHv}_{3}\)
\choice \(\vb*{DGHv}_{3}\)
\choice \(\vb*{ABCDHv}_{3}\)
\choice \(\vb*{DEFGHv}_{3}\)
\choice \(\vb*{ABCDEFGHv}_{3}\)
\choice None of the other options is the correct answer
\end{choices}
\begin{solution}
Refer to \cref{question@19}.
\end{solution}
}
\setcounter{question}{21}
\begin{EnvFullwidth}
\vspace{20pt}
Consider the following \textbf{view-transformation matrix}.
\begin{equation*}
\vb*{V} = \begin{pNiceMatrix}[light-syntax]
a b c d;
e f g h;
i j k m;
0 0 0 1
\end{pNiceMatrix}
\end{equation*}
\end{EnvFullwidth}
\question{
\vspace{-30pt}
Which of the following is the matrix that can be used to transform a \textbf{3D vector} from \textbf{world space} to \textbf{view space}?
\begin{choices}
\correctchoice \(\begin{pNiceMatrix}[light-syntax]
a b c;
e f g;
i j k
\end{pNiceMatrix}\)
\choice \(\begin{pNiceMatrix}[light-syntax]
a e i;
b f i;
c j k
\end{pNiceMatrix}\)
\choice \(\begin{pNiceMatrix}[light-syntax]
1/a b c;
e 1/f g;
i j 1/k
\end{pNiceMatrix}\)
\choice \(\begin{pNiceMatrix}[light-syntax]
1/a e i;
b 1/f i;
c j 1/k
\end{pNiceMatrix}\)
\choice \(\begin{pNiceMatrix}[light-syntax]
1/a 1/b 1/c;
1/e 1/f 1/g;
1/i 1/j 1/k
\end{pNiceMatrix}\)
\choice \(\begin{pNiceMatrix}[light-syntax]
1/a 1/e 1/i;
1/b 1/f 1/i;
1/c 1/j 1/k
\end{pNiceMatrix}\)
\choice None of the other options is the correct answer
\end{choices}
\begin{solution}
A view transformation matrix is a rotation, followed by a translation.
A \(4 \times 4\) translation matrix and a \(4\times4\) rotation matrix are, respectively:
\begin{align*}
\vb*{T} & = \begin{pNiceMatrix}[light-syntax]
1 0 0 d;
0 1 0 h;
0 0 1 m;
0 0 0 1
\end{pNiceMatrix} & \vb*{R} = \begin{pNiceMatrix}[light-syntax]
a b c 0;
e f g 0;
i j k 0;
0 0 0 1
\end{pNiceMatrix}
\end{align*}
and the view transformation,
\begin{equation*}
\vb*{V} = \vb*{TR} = \begin{pNiceMatrix}[light-syntax]
\Block[fill=orange!15,rounded-corners]{3-3}{}a b c \Block[fill=green!15,rounded-corners]{3-1}{}d;
e f g h;
i j k m;
0 0 0 1
\end{pNiceMatrix}
\end{equation*}
where \textcolor{orange}{orange} represents the rotation submatrix, and \textcolor{green}{green} the translation submatrix.
A \emph{3D vector} has the form \(\pmqty{a & b & c}^{\intercal}\).
Furthermore, \emph{vectors} are not \emph{points}, so translations are undefined. Hence, the answer is \circled{A}.
\end{solution}
\question{
Given the above view-transformation matrix \(\vb*{V}\), which of the following is the matrix that can be used to transform a 3D vector from \textbf{view space} to \textbf{world space}?
\begin{solution}
See \cref{question@22}. The inverse of a rotation matrix \(\vb*{R}\) is its transpose, ie \(\vb*{R}^{-1} = \vb*{R}^{\intercal}\). Hence, we have \circled{B}.
\end{solution}
}
\setcounter{question}{26}
\question{
A line segment from the pixel location \((100,600)\) to \((300,200)\) is scan-converted.
Assuming the line segment is drawn as thin as possible and not broken, what is the number of fragments (pixels that are turned on) that are produced for this line segment?
This number includes the two fragments at the two endpoints of the line segment.
\begin{oneparchoices}
\choice 200
\choice 201
\correctchoice 400
\choice 401
\choice 600
\choice 601
\end{oneparchoices}
\begin{solution}
The line has gradient \(m = -2\) (which should be obvious).
Hence, we choose \(y\) to be the iteration variable.
Working graphically, and supposing the red line below is the line segment to be rasterised:
\begin{center}
\begin{tikzpicture}
\draw[gray,thin,densely dotted,step=1] (-3,6) grid (4, -8);
\fill[red,fill opacity=0.2] (0, 0) rectangle (-1, 1);
\fill[red,fill opacity=0.2] (0, 1) rectangle (-1, 2);
\fill[red,fill opacity=0.2] (-1, 2) rectangle (-2, 3);
\fill[red,fill opacity=0.2] (-1, 3) rectangle (-2, 4);
\fill[red,fill opacity=0.2] (-2, 4) rectangle (-3, 5);
\fill[red,fill opacity=0.2] (-2, 5) rectangle (-3, 6);
\draw[thick,red] (-3, 6) -- (0.2, -0.4);
\draw[densely dashed] (-3, 7) node[anchor=south]{\(x = 100\)} -- (-3, -1) ;
\draw[densely dashed] (-4, 6) node[anchor=east]{\(y = 600\)} -- (1, 6) ;
\node at (0.3, -0.6)[red,anchor=center] {\(\cdot\)};
\node at (0.4, -0.8)[red,anchor=center] {\(\cdot\)};
\node at (0.5, -1)[red,anchor=center] {\(\cdot\)};
\node at (0.6, -1.2)[red,anchor=center] {\(\cdot\)};
\node at (0.7, -1.4)[red,anchor=center] {\(\cdot\)};
\foreach \x [count=\i] in {-2, -1, 0}{
\draw (\x, 6.1) -- (\x, 5.9) node[anchor=south,shift={(0,2mm)}] {\(10\i\)};
}
\foreach \i [evaluate=\i as \y using \i+594] in {5,4,...,0}{
\draw (-3.1, \i) -- (-2.9, \i) node[anchor=east,shift={(-2mm,0)}] {\(\pgfmathprintnumber{\y}\)};
}
\fill[red,fill opacity=0.2] (1, -2) rectangle (2, -3);
\fill[red,fill opacity=0.2] (1, -3) rectangle (2, -4);
\fill[red,fill opacity=0.2] (2, -4) rectangle (3, -5);
\fill[red,fill opacity=0.2] (2, -5) rectangle (3, -6);
\fill[red,fill opacity=0.2] (3, -6) rectangle (4, -7);
\fill[red,fill opacity=0.2] (3, -7) rectangle (4, -8);
\draw[thick,red] (0.8, -1.6) -- (4, -8);
\draw[densely dashed] (4, -9) node[anchor=north]{\(x = 300\)} -- (4, -1);
\draw[densely dashed] (0, -8) -- (5, -8) node[anchor=west]{\(y = 200\)} ;
\node at (0.3, -0.6)[red,anchor=center] {\(\cdot\)};
\node at (0.4, -0.8)[red,anchor=center] {\(\cdot\)};
\node at (0.5, -1)[red,anchor=center] {\(\cdot\)};
\foreach \i [evaluate=\i as \x using \i+296] in {1,2,3}{
\draw (\i, -8.1) -- (\i, -7.9) node[anchor=north,shift={(0,-2mm)}] {\(\pgfmathprintnumber{\x}\)};
}
\foreach \i [evaluate=\i as \y using \i+208] in {-2,-3,...,-7}{
\draw (3.9, \i) -- (4.1, \i) node[anchor=west] {\(\pgfmathprintnumber{\y}\)};
}
\end{tikzpicture}
\end{center}
Therefore, \circled{C} is correct.
\end{solution}
}
}
\end{questions}
\end{document}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment