Repository: alexpovel/latex-cookbook Branch: main Commit: 13bd8e4d8782 Files: 63 Total size: 508.9 KB Directory structure: gitextract_sv1rvnjz/ ├── .devcontainer/ │ ├── README.md │ ├── devcontainer.json │ └── image/ │ ├── Dockerfile │ ├── README.md │ ├── config/ │ │ ├── .wgetrc │ │ └── texlive.profile │ └── texlive.sh ├── .gitattributes ├── .github/ │ └── workflows/ │ └── build.yml ├── .gitignore ├── .latexmkrc ├── .vscode/ │ ├── extensions.json │ └── settings.json ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── acp.cls ├── bib/ │ ├── README.md │ ├── bibliography.bib │ └── glossaries/ │ ├── abbreviations.bib │ ├── constants.bib │ ├── index/ │ │ ├── names.bib │ │ └── terms.bib │ └── symbols/ │ ├── greek.bib │ ├── other.bib │ ├── roman.bib │ └── subscripts.bib ├── chapters/ │ ├── README.md │ ├── backmatter.tex │ ├── frontmatter/ │ │ ├── abstract.tex │ │ ├── authorship_declaration.tex │ │ ├── colophon.tex │ │ ├── preface.tex │ │ └── task.tex │ ├── frontmatter.tex │ ├── mainmatter/ │ │ ├── base-features.tex │ │ ├── code-listings.tex │ │ ├── floats.tex │ │ └── usage.tex │ └── mainmatter.tex ├── cookbook.tex ├── data/ │ ├── README.md │ ├── diffuser.csv │ ├── matlab2tikz_table_example.tex │ └── matlab2tikz_table_example_data.csv ├── images/ │ ├── bitmaps/ │ │ └── README.md │ └── vectors/ │ └── README.md ├── lib/ │ ├── README.md │ └── example.lua ├── pandoc/ │ ├── README.md │ ├── defaults.yaml │ ├── metadata.yaml │ └── promote-headers.lua └── tests/ ├── Makefile ├── README.md ├── config.yml ├── pyproject.toml └── tests/ ├── __init__.py ├── conftest.py ├── test_pdfs.py ├── test_self.py └── utils.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .devcontainer/README.md ================================================ # Remote: Containers for VSCode This directory contains all files required to enable [working *inside* of containers](https://code.visualstudio.com/docs/remote/containers) in VSCode. The entire workspace/IDE will work from *within* the context of a container of an image of your choice. ================================================ FILE: .devcontainer/devcontainer.json ================================================ { "name": "LaTeX", // Instead of *building* the accompanying Dockerfile and its whole context, like: // // "build": { // "context": "..", // "dockerfile": "image/Dockerfile" // }, // // simply download the prepared image the author has already uploaded, based on // what's found inside the `image/` directory. // Advantages: // - build process is slow (downloads from TeX servers), each user doing it every // time is too much. It can take *hours* in worst-cases // - build might fail for various reasons // It is much easier to download the ready-made image. // Disadvantages: // - cannot easily iterate on the Docker image, need to go through Docker Hub. // Recourse: simply change the below to use the *local image temporarily* // - Upstream image on Docker Hub might not be the latest "image": "alexpovel/latex", "customizations": { "vscode": { // Set *default* container specific settings.json values on container create. "settings": { "terminal.integrated.defaultProfile.linux": "bash" }, // Add the IDs of extensions you want installed when the container is created. // Browse for extensions here: https://marketplace.visualstudio.com/ // then look for 'Unique Identifier' on the extension's page. "extensions": [ "James-Yu.latex-workshop", "streetsidesoftware.code-spell-checker", "streetsidesoftware.code-spell-checker-german" ] } }, "containerEnv": { // Inside the container, act as though we're in CI. Important for the Makefile. "CI": "true", // The base image has this locale: // $ docker run --rm --entrypoint="locale" alexpovel/latex // LANG= // LANGUAGE= // LC_CTYPE="POSIX" // LC_NUMERIC="POSIX" // LC_TIME="POSIX" // LC_COLLATE="POSIX" // LC_MONETARY="POSIX" // LC_MESSAGES="POSIX" // LC_PAPER="POSIX" // LC_NAME="POSIX" // LC_ADDRESS="POSIX" // LC_TELEPHONE="POSIX" // LC_MEASUREMENT="POSIX" // LC_IDENTIFICATION="POSIX" // LC_ALL= // *However*, starting this very same container in VSCode's Remote Containers, // the locale changes to: // $ locale // locale: Cannot set LC_CTYPE to default locale: No such file or directory // locale: Cannot set LC_MESSAGES to default locale: No such file or directory // locale: Cannot set LC_ALL to default locale: No such file or directory // LANG=en_US.UTF-8 // LANGUAGE= // LC_CTYPE="en_US.UTF-8" // LC_NUMERIC="en_US.UTF-8" // LC_TIME="en_US.UTF-8" // LC_COLLATE="en_US.UTF-8" // LC_MONETARY="en_US.UTF-8" // LC_MESSAGES="en_US.UTF-8" // LC_PAPER="en_US.UTF-8" // LC_NAME="en_US.UTF-8" // LC_ADDRESS="en_US.UTF-8" // LC_TELEPHONE="en_US.UTF-8" // LC_MEASUREMENT="en_US.UTF-8" // LC_IDENTIFICATION="en_US.UTF-8" // LC_ALL= // There's three errors because the container doesn't seem to have the correct // locale files: // $ locale -a // locale: Cannot set LC_CTYPE to default locale: No such file or directory // locale: Cannot set LC_MESSAGES to default locale: No such file or directory // locale: Cannot set LC_COLLATE to default locale: No such file or directory // C // C.UTF-8 // POSIX // This leads to `lualatex` erroring out, see also https://tex.stackexchange.com/q/374303/120853 // Using "POSIX" is possible and brings us back to vanilla container locale: "LC_ALL": "POSIX" } } ================================================ FILE: .devcontainer/image/Dockerfile ================================================ # ARGs before the first FROM are global and usable in all stages ARG BASE_OS="debian" # Tag of the base OS image ARG OS_VERSION="testing" # TeXLive version. This will be used by the `texlive.sh` script to determine what to # download and install. `latest` will fetch the latest version available on their servers. # Alternatively, you can specify *a past year* and it will download that version # from the TeXLive archives and use it (can take a long time). # For available years, see ftp://tug.org/historic/systems/texlive/ . ARG TL_VERSION="latest" ARG _BUILD_CONTEXT_PREFIX=".devcontainer/image/" # Image with layers as used by all succeeding steps FROM ${BASE_OS}:${OS_VERSION} as base # Use `apt-get` over just `apt`, see https://askubuntu.com/a/990838/978477. # Also run `apt-get update` on every `RUN`, see: # https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run RUN apt-get update && \ apt-get install --yes --no-install-recommends \ # wget for `install-tl` script to download TeXLive, and other downloads. wget \ # In a similar vein, `curl` is required by various tools, or is just very # nice to have for various scripting tasks. curl \ # wget/install-tl requires capability to check certificate validity. # Without this, executing `install-tl` fails with: # # install-tl: TLPDB::from_file could not initialize from: https:///pub/ctan/systems/texlive/tlnet/tlpkg/texlive.tlpdb # install-tl: Maybe the repository setting should be changed. # install-tl: More info: https://tug.org/texlive/acquire.html # # Using `install-tl -v`, found out that mirrors use HTTPS, for which the # underlying `wget` (as used by `install-tl`) returns: # # ERROR: The certificate of '' is not trusted. # ERROR: The certificate of '' doesn't have a known issuer. # # This is resolved by installing: ca-certificates \ # Update Perl, otherwise: "Can't locate Pod/Usage.pm in @INC" in install-tl # script; Perl is already installed, but do not use `upgrade`, see # https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run perl \ # Install `latexindent` Perl dependencies. # Found these using this method: https://unix.stackexchange.com/a/506964/374985 # List of `latexindent` dependencies is here: # https://latexindentpl.readthedocs.io/en/latest/appendices.html#linux, # see also the helper script at # https://github.com/cmhughes/latexindent.pl/blob/master/helper-scripts/latexindent-module-installer.pl # # Installing via Debian system packages because installing the modules via # `cpanm` requires `gcc` and I wanted to avoid installing that (~200MB). # # YAML::Tiny: libyaml-tiny-perl \ # File::HomeDir: libfile-homedir-perl \ # Unicode:GCString: libunicode-linebreak-perl \ # Log::Log4perl: liblog-log4perl-perl \ # Log::Dispatch: liblog-dispatch-perl \ # Usually, `latexmk` is THE tool to use to automate, in a `make`-like style, # LaTeX (PDF) file generation. However, if that is not enough, the following # will fill the gaps and cover all other use cases: make \ # Get `envsubst` to replace environment variables in files with their actual # values. gettext-base \ # Using the LaTeX package `minted` for syntax highlighting of source code # snippets. It's much more powerful than the alternative `listings` (which is # pure TeX: no outside dependencies but limited functionality) but requires # Python's `pygments` package: python3 \ python3-pygments \ # Required to embed git metadata into PDF from within Docker container: git \ # Required to use pdfunite for merging PDF files. Ghostscript is causing # trouble with Mozilla Firefox's PDF Reader. poppler-utils # The `minted` LaTeX package provides syntax highlighting using the Python `pygmentize` # package. That package also installs a callable script, which `minted` uses, see # https://tex.stackexchange.com/a/281152/120853. # Therefore, `minted` primarily works by invoking `pygmentize` (or whatever it was # overridden by using `\MintedPygmentize`). However, it requires `python` for other # jobs, e.g. to remove leading whitespace for the `autogobble` function, see the # "\minted@autogobble Remove common leading whitespace." line in the docs. # It is invoked with `python -c`, but Debian only has `python3`. Therefore, alias # `python` to invoke `python3`. Use `update-alternatives` because it's cooler than # symbolic linking, and made for this purpose. # If `python` is not available but `pygmentize` is, stuff like `autogobble` and # `\inputminted`won't work but syntax highlighting will. # See also https://stackoverflow.com/a/55351449/11477374 # Last argument is `priority`, whose value shouldn't matter since there's nothing else. RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 1 FROM base as downloads # Cannot share ARGs over multiple stages, see also: # https://github.com/moby/moby/issues/37345. # Therefore, work in root (no so `WORKDIR`), so in later stages, the location of # files copied from this stage does not have to be guessed/WET. # Using an ARG with 'TEX' in the name, TeXLive will warn: # # ---------------------------------------------------------------------- # The following environment variables contain the string "tex" # (case-independent). If you're doing anything but adding personal # directories to the system paths, they may well cause trouble somewhere # while running TeX. If you encounter problems, try unsetting them. # Please ignore spurious matches unrelated to TeX. # TEXPROFILE_FILE=texlive.profile # ---------------------------------------------------------------------- # # This also happens when the *value* contains 'TEX'. # `ARG`s are only set during Docker image build-time, so this warning should be void. # Renew (https://stackoverflow.com/a/53682110): ARG TL_VERSION ARG _BUILD_CONTEXT_PREFIX ARG TL_INSTALL_ARCHIVE="install-tl-unx.tar.gz" ARG EISVOGEL_ARCHIVE="Eisvogel.tar.gz" ARG INSTALL_TL_DIR="install-tl" COPY ./${_BUILD_CONTEXT_PREFIX}/texlive.sh . RUN \ # Get appropriate installer for the TeXLive version to be installed: ./texlive.sh get_installer ${TL_VERSION} && \ # Get Eisvogel LaTeX template for pandoc, # see also #175 in that repo. wget https://github.com/Wandmalfarbe/pandoc-latex-template/releases/latest/download/${EISVOGEL_ARCHIVE} RUN \ mkdir ${INSTALL_TL_DIR} && \ # Save archive to predictable directory, in case its name ever changes; see # https://unix.stackexchange.com/a/11019/374985. # The archive comes with a name in the form of 'install-tl-YYYYMMDD' from the source, # which is of course unpredictable. tar --extract --file=${TL_INSTALL_ARCHIVE} --directory=${INSTALL_TL_DIR} --strip-components 1 && \ \ # Prepare Eisvogel pandoc template (yields `eisvogel.latex` among other things): tar --extract --file=${EISVOGEL_ARCHIVE} FROM base as main # Renew (https://stackoverflow.com/a/53682110): ARG TL_VERSION ARG _BUILD_CONTEXT_PREFIX ARG TL_PROFILE="texlive.profile" # Auxiliary, intermediate file: ARG TMP_TL_PROFILE="${TL_PROFILE}.tmp" # Layer with graphical and auxiliary tools # Put as early as possible in Dockerfile since this should rarely change (cache-friendly) RUN apt-get update && \ apt-get install --yes --no-install-recommends \ # cannot use `default-jre-headless` version (25% of normal size), see # https://github.com/alexpovel/latex-cookbook/issues/17 default-jre \ # No headless inkscape available currently: inkscape \ # nox (no X Window System): CLI version, 10% of normal size: gnuplot-nox \ # For various conversion tasks, e.g. EPS -> PDF (for legacy support): ghostscript # Pandoc layer; not required for LaTeX compilation, but useful for document conversions # Put as early as possible in Dockerfile since this should rarely change (cache-friendly) RUN apt-get update && \ apt-get install --yes --no-install-recommends \ # librsvg2 for 'rsvg-convert' used by pandoc to convert SVGs when embedding # into PDF librsvg2-bin \ pandoc # User to install and run LaTeX as. # This is a security and convenience measure: by default, containers run as root. # To work and compile PDFs using this container, you will need to map volumes into it # from your host machine. Those bind-mounts will then be accessed as root from this # container, and any generated files will also be owned by root. This is inconvenient at # best and dangerous at worst. # The generated user here will have IDs of 1000:1000. If your local user also has those # (the case for single-user Debians etc.), your local user will already have correct # ownership of all files generated by the user we create here. ARG USER="tex" RUN useradd --create-home ${USER} # Label according to http://label-schema.org/rc1/ to have some metadata in the image. # This is important e.g. to know *when* an image was built. Depending on that, it can # contain different software versions (even if the base image is specified as a fixed # version). LABEL \ maintainer="Alex Povel " \ org.label-schema.description="TeXLive with most packages, JavaRE, Inkscape, pandoc and more" \ org.label-schema.vcs-url="https://github.com/alexpovel/latex-cookbook" \ org.label-schema.schema-version="1.0" ARG INSTALL_DIR="/install" WORKDIR ${INSTALL_DIR} # Copy custom file containing TeXLive installation instructions COPY ${_BUILD_CONTEXT_PREFIX}/config/${TL_PROFILE} ${TMP_TL_PROFILE} COPY --from=downloads /install-tl/ /texlive.sh ./ # Move to where pandoc looks for templates, see https://pandoc.org/MANUAL.html#option--data-dir COPY --from=downloads /eisvogel.latex /home/${USER}/.pandoc/templates/ # Global wget config file, see the comments in that file for more info and the rationale. # Location of that file depends on system, e.g.: https://askubuntu.com/a/368050 COPY ${_BUILD_CONTEXT_PREFIX}/config/.wgetrc /etc/wgetrc # "In-place" `envsubst` run is a bit more involved, see also: # https://stackoverflow.com/q/35078753/11477374. # Do not use `mktemp`, will break Docker caching since it's a new file each time. RUN cat "$TMP_TL_PROFILE" | envsubst | tee "$TL_PROFILE" && \ rm "$TMP_TL_PROFILE" # (Large) LaTeX layer RUN ./texlive.sh install "$TL_VERSION" # Remove no longer needed installation workdir. # Cannot run this earlier because it would be recreated for any succeeding `RUN` # instructions. # Therefore, change `WORKDIR` first, then delete the old one. WORKDIR /${USER} USER ${USER} # Load font cache, has to be done on each compilation otherwise # ("luaotfload | db : Font names database not found, generating new one."). # If not found, e.g. TeXLive 2012 and earlier, simply skip it. Will return exit code # 0 and allow the build to continue. # Warning: This is USER-specific. If the current `USER` for which we run this is not # the container user, the font will be regenerated for that new user. RUN luaotfload-tool --update || echo "luaotfload-tool did not succeed, skipping." # Make our class file available for the entire latex/TeXLive installation, see also # https://tex.stackexchange.com/a/1138/120853 COPY acp.cls /home/${USER}/texmf/tex/latex/ USER root # Give back control to own user files; might be root-owned from previous copying processes RUN chown --recursive ${USER}:${USER} /home/${USER}/ USER ${USER} # The default parameters to the entrypoint; overridden if any arguments are given to # `docker run`. # `lualatex` usage for `latexmk` implies PDF generation, otherwise DVI is generated. CMD [ "--lualatex" ] # Allow container to run as an executable; override with `--entrypoint`. # Allows to simply `run` the image without specifying any executable. # If `latexmk` is called without a file argument, it will run on all *.tex files found. ENTRYPOINT [ "latexmk" ] ================================================ FILE: .devcontainer/image/README.md ================================================ # Docker image with custom, almost-full TeXLive distribution & various tools [![Docker Pulls](https://img.shields.io/docker/pulls/alexpovel/latex)](https://hub.docker.com/r/alexpovel/latex) Serves a lot of needs surrounding LaTeX file generation and handling. For the rationale behind the installed Debian packages, see [below](#custom-tools). To see how to build the image, also see [below](#building). ## Quick Intro If you use [VSCode Remote Containers](https://code.visualstudio.com/docs/remote/containers), the below does not apply. There is no need to run manual `docker` invocations on the host. --- [Install Docker](https://docs.docker.com/get-docker/), navigate to your project directory, then run the image as follows: - Bash: ```bash docker run --rm --volume $(pwd):/tex alexpovel/latex ``` - PowerShell: ```powershell docker run --rm --volume ${PWD}:/tex alexpovel/latex ``` The parts making up the command are: - The last line is the location on [DockerHub](https://hub.docker.com/repository/docker/alexpovel/latex). Without specifying a [*tag*](https://hub.docker.com/repository/docker/alexpovel/latex/tags?page=1), the default `latest` is implied. See [below](#historic-builds) for more options. - The `--rm` option removes the container after a successful run. This is generally desired since containers are not supposed to be stateful: once their process terminates, the container terminates, and it can be considered junk. - Providing a `--volume`, in this case the current working directory aka pwd, is required for the container to find files to work on. It has to be *mounted* to a location *inside* the container. This has to be whatever the last `WORKDIR` instruction in the [Dockerfile](Dockerfile) is, e.g. `/tex`. Otherwise, you can always override the `WORKDIR` using the `--workdir` option. This is the directory in which the Docker container's process works in and expects to find files. - Note that there is no command given, e.g. there is nothing *after* `alexpovel/latex`. In this form, the container runs as an executable (just as if you ran `lualatex` or similar commands), where the program to be executed is determined by the `ENTRYPOINT` instruction in the [Dockerfile](Dockerfile). For example, if the `ENTRYPOINT` is set to `latexmk`, running the above command will execute `latexmk` in the container's context, without you having to specify it. (`latexmk` is a recipe-like tool that automates LaTeX document compilation by running `lualatex`, `biber` and whatever else required for compilation as many times as needed for proper PDF output (so references like `??` in the PDF are resolved). It does this by detecting that auxiliary files no longer change (steady-state). The tool is best configured using its config file, `.latexmkrc`.) Any options to the `ENTRYPOINT` executable are given at the end of the command, e.g.: ```bash docker run --rm --volume $(pwd)/tests:/tex alexpovel/latex -c ``` to run, if `latexmk` is the `ENTRYPOINT`, the equivalent of `latexmk -c` ([cleaning auxiliary files](https://mg.readthedocs.io/latexmk.html#cleaning-up)). To **overwrite** the `ENTRYPOINT`, e.g. because you want to run only `lualatex`, use the `--entrypoint` option, e.g. `--entrypoint="lualatex"`. Similarly, you can work inside of the container directly, e.g. for debugging, using `--entrypoint="bash"`. ### Image For the above to work, the `alexpovel/latex` image needs to be available on whatever your default image registry is (usually [DockerHub](https://hub.docker.com/)). If it's not available for pulling (i.e., downloading) from there, you can build this image locally, see [below](#building). ## Approach This Dockerfile is based on a custom TeXLive installer using their [`install-tl` tool](https://www.tug.org/texlive/doc/install-tl.html), instead of [Debian's `texlive-full`](https://packages.debian.org/search?searchon=names&keywords=texlive-full). Other, smaller `texlive-` collections would be [available](https://packages.debian.org/search?suite=default§ion=all&arch=any&searchon=names&keywords=texlive), but TeXLive cannot install missing packages on-the-fly, [unlike MiKTeX](https://miktex.org/howto/miktex-console/). Therefore, images should come with all desirable packages in place; installing them after the fact in running containers using [`tlmgr`](https://www.tug.org/texlive/tlmgr.html) is the wrong approach (containers are only meant to be run; if they are incomplete, modify the *image*, ordinarily by modifying the `Dockerfile`). This approach has the following advantages: - Using ["vanilla" TeXLive](https://www.tug.org/texlive/debian.html) affords us the latest packages directly from the source, while the official Debian package might lag behind a bit. This is often not relevant, but has bitten me several times while working with the latest packages. - The installation can be adjusted better. For example, *multiple GBs* of storage/image size are saved by omitting unneeded PDF documentation files. - We can install arbitrary TeXLive versions, as long as they are the [current](https://tug.org/texlive/acquire-netinstall.html) or an archived () version. Otherwise, to obtain [older or even obsolete TeXLive installations](#historic-builds), one would have to also obtain a corresponding Debian version. This way, we can choose a somewhat recent Debian version and simply install an old TeXLive into it. Eligible archive versions are those year directories (`2019`, `2020`, ...) present at the above FTP link that have a `tlnet-final` subdirectory. This is (speculating here) a frozen, aka final, version, put online the day the *next* major release goes live. For example, version `2021` released on 2021-04-01 and `2020` received its `tlnet-final` subdirectory that same day. The `install-tl` tool is configured via a [*Profile* file](config/texlive.profile), see also the [documentation](https://www.tug.org/texlive/doc/install-tl.html#PROFILES). This enables unattended, pre-configured installs, as required for a Docker installation. --- The (official?) [`texlive/texlive` image](https://hub.docker.com/r/texlive/texlive) follows [the same approach](https://hub.docker.com/layers/texlive/texlive/latest/images/sha256-70fdbc1d9596c8eeb4a80c71a8eb3a5aeb63bed784112cbdb87f740e28de7a80?context=explore). However, there are a bunch of things this Dockerfile does differently that warrant not building `FROM` that image: - a user-editable, thus more easily configurable [profile](config/texlive.profile). This is mainly concerning the picked package *collections*. Unchecking (putting a `0`) unused ones saves around 500MB at the time of writing. - more elaborate support for [historic versions](#historic-builds) - an installation procedure incorporating a proper `USER` Things they do that do not happen here: - verify download integrity using `gpg` ### Historic Builds LaTeX is a slow world, and many documents/templates in circulation still rely on outdated practices or packages. This can be a huge hassle. Maintaining an old LaTeX distribution next to a current one on the same host is not fun. This is complicated by the fact that (La)TeX seems to do things differently than pretty much everything else. For this, Docker is the perfect tool. This image can be built (`docker build`) with different build `ARG`s, and the build process will figure out the proper way to handle installation. There is a [script](texlive.sh) to handle getting and installing TeXLive from the proper location ([current](https://www.tug.org/texlive/acquire-netinstall.html) or [archive](ftp://tug.org/historic/systems/texlive/)). Refer to the [Dockerfile](Dockerfile) for the available `ARG`s (all `ARG` have a default). These are handed to the build process via the [`--build-arg` option](https://docs.docker.com/engine/reference/commandline/build/#options). Note that for a *specific* TeXLive version to be picked, it needs to be present in their [archives](ftp://tug.org/historic/systems/texlive/). The *current* TeXLive is not present there (it's not historic), but is available under the `latest` Docker tag. As such, if for example `2020` is the *current* TeXLive, and the image is to be based on Debian 10, there is *no* `debian-10-texlive-2020` tag. You would obtain this using the `latest` tag. As soon as TeXLive 2020 is superseded and consequently moved to the archives, the former tag can become available. To build an array of different versions automatically, DockerHub provides [advanced options](https://docs.docker.com/docker-hub/builds/advanced/) in the form of hooks, e.g. a [build hook](hooks/build). These are bash scripts that override the default DockerHub build process. At build time, DockerHub provides [environment variables](https://docs.docker.com/docker-hub/builds/advanced/#environment-variables-for-building-and-testing) which can be used in the build hook to forward these into the Dockerfile build process. As such, by just specifying the image *tags* on DockerHub, we can build corresponding images automatically (see also [here](https://web.archive.org/web/20201005132636/https://dev.to/samuelea/automate-your-builds-on-docker-hub-by-writing-a-build-hook-script-13fp)). For more info on this, see [below](#on-dockerhub). The approximate [matching of Debian to TeXLive versions](https://www.tug.org/texlive/debian.html) is (see also [here](https://www.debian.org/releases/) and [here](https://www.debian.org/distrib/archive).): | Debian Codename | Debian Version | TeXLive Version | | --------------- | :------------: | :-------------: | | bullseye | 11 | 2020 | | buster | 10 | 2018 | | stretch | 9 | 2016 | | jessie | 8 | 2014 | | wheezy | 7 | 2012 | | squeeze | 6.0 | 2009 | | lenny | 5.0 | unknown | | etch | 4.0 | unknown | | sarge | 3.1 | unknown | | woody | 3.0 | unknown | | potato | 2.2 | unknown | | slink | 2.1 | unknown | | hamm | 2.0 | unknown | This is only how the official Debian package is shipped. These versions can be, to a narrow extend, freely mixed. Using `install-tl`, older versions of TeXLive can be installed on modern Debian versions. #### Issues Using [*obsolete* Debian releases](https://www.debian.org/releases/) comes with a long list of headaches. As such, Debian versions do not reach too far back. It does not seem worth the effort. Instead, it seems much easier to install older TeXLive versions onto reasonably recent Debians. Issues I ran into are: - `apt-get update` will fail if the original Debian repository is dead (Debian 6/TeXLive 2014): ```plaintext W: Failed to fetch http://httpredir.debian.org/debian/dists/squeeze/main/binary-amd64/Packages.gz 404 Not Found W: Failed to fetch http://httpredir.debian.org/debian/dists/squeeze-updates/main/binary-amd64/Packages.gz 404 Not Found W: Failed to fetch http://httpredir.debian.org/debian/dists/squeeze-lts/main/binary-amd64/Packages.gz 404 Not Found E: Some index files failed to download, they have been ignored, or old ones used instead. ``` As such, there needs to be a [dynamic way to update `/etc/apt/sources.list`](https://github.com/alexpovel/latex-extras-docker/blob/fa9452c236079a65563daff22767b2b637dd80c6/adjust_sources_list.sh) if the Debian version to be used in an archived one, see also [here](https://web.archive.org/web/20201007095943/https://www.prado.lt/using-old-debian-versions-in-your-sources-list). - `RUN wget` (or `curl` etc.) via `HTTPS` will fail for older releases, e.g. GitHub rejected the connection due to the outdated TLS version of the old release (Debian 6/TeXLive 2015): ```text Connecting to github.com|140.82.121.4|:443... connected. OpenSSL: error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version ``` - Downloading older releases requires using the [Debian archives](http://archive.debian.org/debian/). This works fine, however a warning is issued (Debian 6/TeXLive 2014): ```plaintext W: GPG error: http://archive.debian.org squeeze Release: The following signatures were invalid: KEYEXPIRED 1520281423 KEYEXPIRED 1501892461 ``` Probably related to this, the installation then fails: ```plaintext WARNING: The following packages cannot be authenticated! libgdbm3 libssl0.9.8 wget libdb4.7 perl-modules perl openssl ca-certificates E: There are problems and -y was used without --force-yes ``` According to `man apt-get`, `--force-yes` is both deprecated and absolutely not recommended. The correct course here is to `--allow-unauthenticated`, however this would also affect the build process for modern versions, where authentication *did not* fail. The official Debian archives are probably trustworthy, but this is still an issue. - A more obscure issue is (Debian 7/TeXLive 2011): ```plaintext The following packages have unmet dependencies: perl : Depends: perl-base (= 5.14.2-21+deb7u3) but 5.14.2-21+deb7u6 is to be installed E: Unable to correct problems, you have held broken packages. ``` While the error message itself is crystal-clear, debugging this is probably a nightmare. - Tools like `pandoc`, which was released in [2006](https://pandoc.org/releases.html), limit the earliest possible Debian version as long as the tool's installation is part of the Dockerfile. In this example, 2006 should in any case be early enough (if not, update your LaTeX file to work with more recent versions, that is probably decidedly less work). ## Custom Tools The auxiliary tools are (for the actual, up-to-date list, see the [Dockerfile](Dockerfile)): - A *Java Runtime Environment* for [`bib2gls`](https://ctan.org/pkg/bib2gls) from the [`glossaries-extra` package](https://www.ctan.org/pkg/glossaries-extra). `bib2gls` takes in `*.bib` files with glossary, symbol, index and other definitions and applies sorting, filtering etc. For this, it requires Java. - [`inkscape`](https://inkscape.org/) because the [`svg`](https://ctan.org/pkg/svg) package needs it. We only require the CLI, however there is no "no-GUI" version available. Headless Inkscape is [currently in the making](https://web.archive.org/web/20201007100140/https://wiki.inkscape.org/wiki/index.php/Future_Architecture). Using that package, required PDFs and PDF_TEXs are only generated at build-time (on the server or locally) and treated as a cache. As such, they can be discarded freely and are regenerated in the next compilation run, using `svg`, which calls `inkscape`. Therefore, the `svg` package gets rid of all the PDF/PDF_TEX intermediate junk and lets us deal with the true source -- `*.svg` files -- directly. These files are really [XML](https://en.wikipedia.org/wiki/Scalable_Vector_Graphics), ergo text-based, ergo suitable for VCS like `git` (as opposed to binary PDFs). Being an external tool, `svg`/`inkscape` also requires the `--shell-escape` option to `lualatex` etc. for writing outside files. - [`gnuplot`](http://www.gnuplot.info/) for `contour gnuplot` commands for `addplot3` in `pgfplots`. So essentially, an external add-on for the magnificent `pgfplots` package. For `gnuplot` to write computed results to a file for `pgfplots` to read, `--shell-escape` is also required. - [`pandoc`](https://pandoc.org/) as a very flexible, convenient markup conversion tool. For example, it can convert Markdown (like this very [README](README.md)) to PDF via LaTeX: ```bash pandoc README.md --output=README.pdf # pandoc infers what to do from suffixes ``` The default output is usable, but not very pretty. This is where *templates* come into play. A very tidy and well-made such template is [*Eisvogel*](https://github.com/Wandmalfarbe/pandoc-latex-template). Its installation is not via a (Debian) package, so it has to be downloaded specifically. For this, additional requirements are: - `wget` to download the archive, - `librsvg2-bin` for the `rsvg-convert` tool. This is used by `pandoc` to convert SVGs when embedding them into the new PDF. Note that `pandoc` and its *Eisvogel* template can draw [metadata from a YAML header](https://pandoc.org/MANUAL.html#metadata-variables), for example: ```yaml --- title: "Title" author: [Author] date: "YYYY-MM-DD" subject: "Subject" keywords: [Keyword1, Keyword2] lang: "en" ... ``` among other metadata variables. *Eisvogel* uses it to fill the document with info, *e.g.* the PDF header and footer. `pandoc` is not required for LaTeX work, but is convenient to have at the ready for various conversion jobs. ## Building The proper way to access these images is via DockerHub. ### On DockerHub ([Requires Pro Plan](https://docs.docker.com/docker-hub/builds/)) This repository and its [Dockerfile](Dockerfile) used to be built into the corresponding image continuously and made available on [DockerHub](https://hub.docker.com/repository/docker/alexpovel/latex). This process now requires a Pro plan and was therefore retired. For the currently available tags, see [here](https://hub.docker.com/repository/docker/alexpovel/latex/tags?page=1). ### Locally The Dockerfile is now built locally and pushed manually. Refer to the Dockerfile for all the available configuration environment variables (`ARG`s). The build can take a very long time (if you have all collections selected in the [profile](config/texlive.profile)), especially when downloading from the TeXLive/TUG archives. For developing/debugging, it is advisable to download the archive files once. E.g. for TexLive 2014, you would want this directory: . Download in one go using: ```bash wget --recursive --no-clobber ftp://tug.org/historic/systems/texlive/2014/tlnet-final ``` The `--no-clobber` option allows you to restart the download at will. Then, work with the `--repository=/some/local/path` option of `install-tl`, after [copying the archive directory into the image at build time](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#understand-build-context) (see also [here](https://tex.stackexchange.com/a/374651/120853)). Having a local copy circumvents [unstable connections](https://tex.stackexchange.com/q/370686/120853) and minimizes unnecessary load onto TUG servers. ================================================ FILE: .devcontainer/image/config/.wgetrc ================================================ # wget config file # TeXLive uses wget. Make wget as robust as possible here. # Make downloading as robust as possible since TeXLive/TUG servers can be unreliable. # If we leave downloading to the install script, we cannot influence the parameters # and it might fail without retrying and for unfortunate reasons at that (like # failing the entire install an hour in because of one package that failed to # download). All of this is exacerbated using Docker, since we are building remotely # on their infrastructure, which is inaccessible. A failure after 8h of queue and # 2h of build time due to unstable downloads is annoying. # See also: # https://www.gnu.org/software/wget/manual/wget.html#Startup-File # https://superuser.com/a/689340/1144470 # https://www.gnu.org/software/wget/manual/html_node/Sample-Wgetrc.html retry_connrefused = on wait_retry = 120 read_timeout = 20 timeout = 15 tries = 5 # Setting the following option to `on` can give: # install-tl: open tlpdb(ftp://tug.org/historic/systems/texlive/2016/tlnet-final/tlpkg/texlive.tlpdb) failed: Inappropriate ioctl for device at tlpkg/TeXLive/TLPDB.pm line 359. # no-clobber = off ================================================ FILE: .devcontainer/image/config/texlive.profile ================================================ # ------------------------------------------------------------------------------- # TeX Live profile to configure the installation procedure, enabling headless/ # unattended install. # For more info, see: https://www.tug.org/texlive/doc/install-tl.html#PROFILES # ------------------------------------------------------------------------------- # File has to have LF line endings to work with `install-tl` Perl script! # ------------------------------------------------------------------------------- # We do a manual-ish install, do not use premade scheme: selected_scheme scheme-custom # ------------------------------------------------------------------------------- # The below directories are the installation destinations. # An alternative to using the setting here is to set environment variables like # `TEXLIVE_INSTALL_TEXMFHOME` directly (e.g. in the Dockerfile), but as of late, # `install-tl` claims to ignore environment variables when installing from a profile # file ("Environment variables are ignored"): # https://web.archive.org/web/20201122233159/https://www.tug.org/texlive/doc/install-tl.html#OPTIONS # So with this profile file guaranteed to work and parallel environment variables # *maybe* breaking in the future, use this profile file for everything. # Replace the below environment variables with appropriate values (this is automated # in the Dockerfile using `envsubst`). # ------------------------------------------------------------------------------- # See: https://www.tug.org/texlive/doc/install-tl.html#ENVIRONMENT-VARIABLES, # https://tex.stackexchange.com/a/470341/120853. # IMPORTANT: Put these into the actual designated container's user's home for full # write access. Otherwise, we run into all sorts of annoying errors, like # https://tex.stackexchange.com/q/571021/120853. # The user we run this as is specified in the Dockerfile and inserted into here. TEXMFHOME /home/${USER}/texmf TEXMFVAR /home/${USER}/.texlive/texmf-var TEXMFCONFIG /home/${USER}/.texlive/texmf-config # Not required, left at default: # TEXDIR /usr/local/texlive/ # TEXMFSYSCONFIG /usr/local/texlive//texmf-config # TEXMFSYSVAR /usr/local/texlive//texmf-var # TEXMFLOCAL /usr/local/texlive/texmf-local # # ------------------------------------------------------------------------------- # Collections of packages; for their contents, see # http://mirror.ctan.org/systems/texlive/tlnet/tlpkg/texlive.tlpdb # and search for 'name collection-', e.g. 'name collection-basic'. # At the time of writing, the following encompasses all available collections. # Only the core ones with very few supported languages are enabled. For example, # just including 'collection-langjapanese' requires 800MB of space. # ------------------------------------------------------------------------------- collection-basic 1 collection-bibtexextra 1 collection-binextra 1 collection-fontsextra 1 collection-fontsrecommended 1 collection-fontutils 1 collection-formatsextra 1 collection-langenglish 1 collection-langeuropean 1 collection-langgerman 1 collection-latex 1 collection-latexextra 1 collection-latexrecommended 1 collection-luatex 1 collection-mathscience 1 collection-pictures 1 collection-plaingeneric 1 collection-publishers 1 collection-xetex 1 # ------------------------------------------------------------------------------- # Enable the following disabled ones as needed. They are included here so # everyone can see what is available; as many as possible are disabled, since # image size matters. The default is aimed at documents in the sciences domain. # Therefore, everything else is disabled. This includes various languages, so # activate your missing language here! # ------------------------------------------------------------------------------- collection-context 0 collection-games 0 collection-humanities 0 collection-langarabic 0 collection-langchinese 0 collection-langcjk 0 collection-langcyrillic 0 collection-langczechslovak 0 collection-langfrench 0 collection-langgreek 0 collection-langitalian 0 collection-langjapanese 0 collection-langkorean 0 collection-langother 0 collection-langpolish 0 collection-langportuguese 0 collection-langspanish 0 collection-metapost 0 collection-music 0 collection-pstricks 0 collection-texworks 0 collection-wintools 0 # ------------------------------------------------------------------------------- # Options for TeXLive installation # ------------------------------------------------------------------------------- # Create symlinks in standard PATH directories (TeXLive installs into `TEXDIR`, # see its path above). Instead of manipulating PATH, symlinks to `TEXDIR` are # created, per default into `/usr/local/bin`. # This setting is required to find tools! # WARNING: This seems to only have been introduced in TeXLive 2017, see: # https://web.archive.org/web/20171213102459/http://www.tug.org/texlive/doc/install-tl.html # (archives from 2016 and earlier do not mention `adjustpath` on that page). # # At the same time, TeXLive 2020 does not seem to respect the set `TEXDIR`, breaking # installation. However, adjusting the path here automatically works. # Since older installations will simply ignore this setting, enable it for safety. instopt_adjustpath 1 # Do not adjust remote CTAN repository; keep the one manually specified. # Shouldn't matter since the repository is not used after installation/image build. instopt_adjustrepo 0 # A4 default, not letter format instopt_letter 0 # No portable installation required instopt_portable 0 # Required for --shell-escape option, as required by packages, e.g. `svg` instopt_write18_restricted 1 # ------------------------------------------------------------------------------- # Some more documentation for the following options at: # https://tug.org/texlive/doc/tlmgr.html # ------------------------------------------------------------------------------- # Autobackup just fills cache, skip; see # https://tex.stackexchange.com/a/398831/120853 tlpdbopt_autobackup 0 tlpdbopt_backupdir tlpkg/backups # Create font format files, otherwise they have to be created on the fly each # time. tlpdbopt_create_formats 1 # None of the following is required; especially not documentation and source # files, which fill multiple GBs tlpdbopt_desktop_integration 0 tlpdbopt_file_assocs 0 tlpdbopt_generate_updmap 0 tlpdbopt_install_docfiles 0 tlpdbopt_install_srcfiles 0 # # Execute postinstallation code for packages: tlpdbopt_post_code 1 # Symlink destinations (binaries, documentation, manuals). # Since symlinking is done manually in the Dockerfile, these are not needed. # tlpdbopt_sys_bin /usr/local/bin # tlpdbopt_sys_info /usr/local/share/info # tlpdbopt_sys_man /usr/local/share/man ================================================ FILE: .devcontainer/image/texlive.sh ================================================ #!/bin/bash # Script to fetch `install-tl` script from different sources, depending on argument # given. set -ueo pipefail usage() { echo "Usage: $0 get_installer|install latest|version (YYYY)" } # From: https://stackoverflow.com/a/2990533/11477374 echoerr() { echo "$@" 1>&2; } check_path() { # The following test assumes the most basic program, `tex`, is present, see also # https://www.tug.org/texlive/doc/texlive-en/texlive-en.html#x1-380003.5 echo "Checking PATH and installation..." if tex --version then echo "PATH and installation seem OK, exiting with success." exit 0 else echoerr "PATH or installation unhealthy, further action required..." fi } if [[ $# != 2 ]]; then echoerr "Unsuitable number of arguments given." echoerr "Got arguments: $*" usage # From /usr/include/sysexits.h exit 64 fi # Bind CLI arguments to explicit names: ACTION=${1} VERSION=${2} # Download the `install-tl` script from the `tlnet-final` subdirectory, NOT # from the parent directory. The latter contains an outdated, non-final `install-tl` # script, causing this exact problem: # https://tug.org/pipermail/tex-live/2017-June/040376.html HISTORIC_URL="ftp://tug.org/historic/systems/texlive/${VERSION}/tlnet-final" REGULAR_URL="http://mirror.ctan.org/systems/texlive/tlnet" case ${ACTION} in "get_installer") if [[ ${VERSION} == "latest" ]] then # Get from default, current repository GET_URL="${REGULAR_URL}/${TL_INSTALL_ARCHIVE}" else # Get from historic repository GET_URL="${HISTORIC_URL}/${TL_INSTALL_ARCHIVE}" fi wget "$GET_URL" ;; "install") if [[ ${VERSION} == "latest" ]] then # Install using default, current repository. # Install process/script documentation is here: # https://www.tug.org/texlive/doc/texlive-en/texlive-en.html perl install-tl \ --profile="$TL_PROFILE" else # Install using historic repository (`install-tl` script and repository # versions need to match) perl install-tl \ --profile="$TL_PROFILE" \ --repository="$HISTORIC_URL" fi # If automatic `install-tl` process has already adjusted PATH, we are happy. check_path echo "install-tl procedure did not adjust PATH automatically, trying other options..." # `\d` class doesn't exist for basic `grep`, use `0-9`, which is much more # portable. Finding the initial dir is very fast, but looking through everything # else afterwards might take a while. Therefore, print and quit after first result. # Path example: `/usr/local/texlive/2018/bin/x86_64-linux` TEXLIVE_BIN_DIR=$(find / -type d -regextype grep -regex '.*/texlive/[0-9]\{4\}/bin/.*' -print -quit) # -z test: string zero length? if [ -z "$TEXLIVE_BIN_DIR" ] then echoerr "Expected TeXLive installation dir not found and TeXLive installation did not modify PATH automatically." echoerr "Exiting." exit 1 fi echo "Found TeXLive binaries at $TEXLIVE_BIN_DIR" echo "Trying native TeXLive symlinking using tlmgr..." # To my amazement, `tlmgr path add` can fail but still link successfully. So # check if PATH is OK despite that command failing. "$TEXLIVE_BIN_DIR"/tlmgr path add || \ echoerr "Command borked, checking if it worked regardless..." check_path echoerr "Symlinking using tlmgr did not succeed, trying manual linking..." SYMLINK_DESTINATION="/usr/local/bin" # "String contains", see: https://stackoverflow.com/a/229606/11477374 if [[ ! ${PATH} == *${SYMLINK_DESTINATION}* ]] then # Should never get here, but make sure. echoerr "Symlink destination ${SYMLINK_DESTINATION} not in PATH (${PATH}), exiting." exit 1 fi echo "Symlinking TeXLive binaries in ${TEXLIVE_BIN_DIR}" echo "to a directory (${SYMLINK_DESTINATION}) found on PATH (${PATH})" # Notice the slash and wildcard. ln \ --symbolic \ --verbose \ --target-directory="$SYMLINK_DESTINATION" \ "$TEXLIVE_BIN_DIR"/* check_path echoerr "All attempts failed, exiting." exit 1 ;; *) echoerr "Input not understood." usage # From /usr/include/sysexits.h exit 64 esac ================================================ FILE: .gitattributes ================================================ # bib -> latex does not help much, since it is also not valid latex, but at # least highlights comments (%) correctly *.bib linguist-language=latex # Bash is wrong, it is really a plain-text file. # However, it gets us comment highlighting (hiding/grey) and is close enough. *.profile linguist-language=bash # Do not include git config files in archives (e.g. when downloading as ZIP): .git* export-ignore ================================================ FILE: .github/workflows/build.yml ================================================ name: Building and testing on: [push] jobs: building: runs-on: ubuntu-latest container: image: alexpovel/latex # Need root, otherwise this exact issue occurs: # https://github.community/t/permission-problems-when-checking-out-code-as-part-of-github-action/202263 options: --user root steps: - name: Checkout repository uses: actions/checkout@v6 - name: Run preflight checks run: make preflight - name: Build all LaTeX PDFs run: make tex - name: Build README PDF run: make README.pdf - name: Archive compilation artifacts uses: actions/upload-artifact@v7 with: name: pdfs path: ./*.pdf if-no-files-found: error testing: needs: building runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: python-version: "3.14" cache: "pip" - name: Install Python dependencies working-directory: ./tests # Needs to find pyproject.toml file run: > python -m venv .venv && . .venv/bin/activate && pip install . - name: Test the suite itself run: > . ./tests/.venv/bin/activate && make test-self - uses: actions/download-artifact@v8 with: name: pdfs # Specify name, else it'll be downloaded to a subdirectory - name: Test generated PDFs run: > . ./tests/.venv/bin/activate && make test-pdfs ================================================ FILE: .gitignore ================================================ # This file tells git what files *not* to track in its version control. # Specific files, general suffixes, whole directories etc. can be specified. # ====================================================================================== # Python (https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore) # ====================================================================================== # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ cover/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder .pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: # .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # Cython debug symbols cython_debug/ # ====================================================================================== # LaTeX # ====================================================================================== # Generated PDF is not suitable for Git. We get our compiled PDF via CI. # Only ignore root level PDF, since images/vectors might be in PDF format. /*.pdf Eisvogel*/ # Testing environment testing.tex # Some weird junk file from VSCode LaTeX Workshop? __latexindent_temp.tex # Include settings files, but nothing else, since that is used as part of the cookbook .vscode/* !.vscode/settings.json !.vscode/extensions.json organisational/ # Used to generate the 'dirty directory tree' dirty_directory/ # Temporarily generated files using gnuplot (e.g. 'contour gnuplot') with pgfplots. Filenames are of the form '
_contourtmp_. # Extensions are 'dat', 'table', 'script' *contourtmp* # Automatically generated files by svg package: **/svg-inkscape/* ## Core latex/pdflatex auxiliary files: *.aux *.lof *.log # List of Reactions (`chemmacros`): *.lor *.lot *.fls *.out *.toc *.fmt *.fot *.cb *.cb2 .*.lb ## Intermediate documents: *.dvi *.xdv *-converted-to.* # these rules might exclude image files for figures etc. # *.ps # *.eps # *.pdf ## Generated if empty string is given at "Please type another file name for output:" .pdf ## Bibliography auxiliary files (bibtex/biblatex/biber): *.bbl *.bcf *.blg *-blx.aux *-blx.bib *.run.xml ## Build tool auxiliary files: *.fdb_latexmk *.synctex *.synctex(busy) *.synctex.gz *.synctex.gz(busy) *.pdfsync ## Build tool directories for auxiliary files # latexrun latex.out/ ## Auxiliary and intermediate files from other packages: # algorithms *.alg *.loa # achemso acs-*.bib # amsthm *.thm # beamer *.nav *.pre *.snm *.vrb # changes *.soc # comment *.cut # cprotect *.cpt # elsarticle (documentclass of Elsevier journals) *.spl # endnotes *.ent # fixme *.lox # feynmf/feynmp *.mf *.mp *.t[1-9] *.t[1-9][0-9] *.tfm #(r)(e)ledmac/(r)(e)ledpar *.end *.?end *.[1-9] *.[1-9][0-9] *.[1-9][0-9][0-9] *.[1-9]R *.[1-9][0-9]R *.[1-9][0-9][0-9]R *.eledsec[1-9] *.eledsec[1-9]R *.eledsec[1-9][0-9] *.eledsec[1-9][0-9]R *.eledsec[1-9][0-9][0-9] *.eledsec[1-9][0-9][0-9]R # glossaries *.acn *.acr *.glg *.glo *.gls *.glsdefs # gnuplottex *-gnuplottex-* # gregoriotex *.gaux *.gtex # htlatex *.4ct *.4tc *.idv *.lg *.trc *.xref # hyperref *.brf # knitr *-concordance.tex # TODO Comment the next line if you want to keep your tikz graphics files *.tikz *-tikzDictionary # listings *.lol # makeidx *.idx *.ilg *.ind *.ist # minitoc *.maf *.mlf *.mlt *.mtc[0-9]* *.slf[0-9]* *.slt[0-9]* *.stc[0-9]* # minted _minted* *.pyg # morewrites *.mw # nomencl *.nlg *.nlo *.nls # pax *.pax # pdfpcnotes *.pdfpc # sagetex *.sagetex.sage *.sagetex.py *.sagetex.scmd # scrwfile *.wrt # sympy *.sout *.sympy sympy-plots-for-*.tex/ # pdfcomment *.upa *.upb # pythontex *.pytxcode pythontex-files-*/ # tcolorbox *.listing # thmtools *.loe # TikZ & PGF *.dpth *.md5 *.auxlock # todonotes *.tdo # vhistory *.hst *.ver # easy-todo *.lod # xcolor *.xcp # xmpincl *.xmpi # xindy *.xdy # xypic precompiled matrices *.xyc # endfloat *.ttt *.fff # Latexian TSWLatexianTemp* ## Editors: # WinEdt *.bak *.sav # Texpad .texpadtmp # LyX *.lyx~ # Kile *.backup # KBibTeX *~[0-9]* # auto folder when using emacs and auctex ./auto/* *.el # expex forward references with \gathertags *-tags.tex # standalone packages *.sta # tikz externalize with make-list option *.makefile # Glossaries: *.slg *.slo *.sls # Illustrations Custom Environment and Aux File: *.illustrations # from glossaries-extra with bib2gls *.glstex *.syi *.syg # windows thumbnail cache: Thumbs.db ================================================ FILE: .latexmkrc ================================================ #!/bin/env perl # This file contains instructions and configurations for the `latexmk` program. # That program is somewhat like `make`, but tailored to LaTeX. # LaTeX has a distinct characteristic of regularly requiring *multiple runs* of # the same program (e.g. `lualatex`) before the build is finished. # It's a *multi-pass* system. # In the intermediary runs, latex generates auxiliary files responsible for resolving # references, links, tables of content etc. # `latexmk` knows about these dependencies (otherwise we tell it in this very config # file, see below), detects these and runs latex (and other, outside programs) # accordingly. # Now, why do we need *both* `latexmk` and `make`? # Both automate builds. # `latexmk` is not powerful enough to cover all use cases. # `make` is more general and more suitable to be integrated in CI. # For our latex needs, `make` basically only delegates to `latexmk`. # We **do not** call e.g. `lualatex` multiple times manually from `make`: # this logic is left to `latexmk` and `.latexmkrc`. # However, `make` can also do much more, e.g. cover `pandoc`, clean-up operations etc. # Therefore, `make` and `latexmkrc` *together* are just super powerful and useful. # The shebang at the top is only to get syntax highlighting right across GitLab, # GitHub and IDEs. # This file is not meant to be run, but read by `latexmk`. # ====================================================================================== # Perl `latexmk` configuration file # ====================================================================================== # ====================================================================================== # PDF Generation/Building/Compilation # ====================================================================================== # PDF-generating modes are: # 1: pdflatex, as specified by $pdflatex variable (still largely in use) # 2: postscript conversion, as specified by the $ps2pdf variable (useless) # 3: dvi conversion, as specified by the $dvipdf variable (useless) # 4: lualatex, as specified by the $lualatex variable (best) # 5: xelatex, as specified by the $xelatex variable (second best) $pdf_mode = 4; # Treat undefined references and citations as well as multiply defined references as # ERRORS instead of WARNINGS. # This is only checked in the *last* run, since naturally, there are undefined references # in initial runs. # This setting is potentially annoying when debugging/editing, but highly desirable # in the CI pipeline, where such a warning should result in a failed pipeline, since the # final document is incomplete/corrupted. # # However, I could not eradicate all warnings, so that `latexmk` currently fails with # this option enabled. # Specifically, `microtype` fails together with `fontawesome`/`fontawesome5`, see: # https://tex.stackexchange.com/a/547514/120853 # The fix in that answer did not help. # Setting `verbose=silent` to mute `microtype` warnings did not work. # Switching between `fontawesome` and `fontawesome5` did not help. $warnings_as_errors = 0; # Show used CPU time. Looks like: https://tex.stackexchange.com/a/312224/120853 $show_time = 1; # Default is 5; we seem to need more owed to the complexity of the document. # Actual documents probably don't need this many since they won't use all features, # plus won't be compiling from cold each time. $max_repeat=7; # --shell-escape option (execution of code outside of latex) is required for the #'svg' package. # It converts raw SVG files to the PDF+PDF_TEX combo using InkScape. # # SyncTeX allows to jump between source (code) and output (PDF) in IDEs with support # (many have it). A value of `1` is enabled (gzipped), `-1` is enabled but uncompressed, # `0` is off. # Testing in VSCode w/ LaTeX Workshop only worked for the compressed version. # Adjust this as needed. Of course, only relevant for local use, no effect on a remote # CI pipeline (except for slower compilation, probably). # # %O and %S will forward Options and the Source file, respectively, given to latexmk. # # `set_tex_cmds` applies to all *latex commands (latex, xelatex, lualatex, ...), so # no need to specify these each. This allows to simply change `$pdf_mode` to get a # different engine. Check if this works with `latexmk --commands`. set_tex_cmds("--shell-escape --synctex=1 %O %S"); # option 2 is same as 1 (run biber when necessary), but also deletes the # regeneratable bbl-file in a clenaup (`latexmk -c`). Do not use if original # bib file is not available! $bibtex_use = 2; # default: 1 # Change default `biber` call, help catch errors faster/clearer. See # https://web.archive.org/web/20200526101657/https://www.semipol.de/2018/06/12/latex-best-practices.html#database-entries $biber = "biber --validate-datamodel %O %S"; # ====================================================================================== # Auxiliary Files # ====================================================================================== # Let latexmk know about generated files, so they can be used to detect if a # rerun is required, or be deleted in a cleanup. # loe: List of Examples (KOMAScript) # lol: List of Listings (`listings` and `minted` packages) # run.xml: biber runs # glg: glossaries log # glstex: generated from glossaries-extra push @generated_exts, 'loe', 'lol', 'lor', 'run.xml', 'glg', 'glstex'; # Also delete the *.glstex files from package glossaries-extra. Problem is, # that that package generates files of the form "basename-digit.glstex" if # multiple glossaries are present. Latexmk looks for "basename.glstex" and so # does not find those. For that purpose, use wildcard. # Also delete files generated by gnuplot/pgfplots contour plots # (.dat, .script, .table). $clean_ext = "%R-*.glstex %R_contourtmp*.*"; # ====================================================================================== # bib2gls as a custom dependency # ====================================================================================== # Grabbed from latexmk CTAN distribution: # Implementing glossary with bib2gls and glossaries-extra, with the # log file (.glg) analyzed to get dependence on a .bib file. # !!! ONLY WORKS WITH VERSION 4.54 or higher of latexmk # Add custom dependency. # latexmk checks whether a file with ending as given in the 2nd # argument exists ('toextension'). If yes, check if file with # ending as in first argument ('fromextension') exists. If yes, # run subroutine as given in fourth argument. # Third argument is whether file MUST exist. If 0, no action taken. add_cus_dep('aux', 'glstex', 0, 'run_bib2gls'); # PERL subroutine. $_[0] is the argument (filename in this case). # File from author from here: https://tex.stackexchange.com/a/401979/120853 sub run_bib2gls { if ( $silent ) { # my $ret = system "bib2gls --silent --group '$_[0]'"; # Original version my $ret = system "bib2gls --silent --group $_[0]"; # Runs in PowerShell } else { # my $ret = system "bib2gls --group '$_[0]'"; # Original version my $ret = system "bib2gls --group $_[0]"; # Runs in PowerShell }; my ($base, $path) = fileparse( $_[0] ); if ($path && -e "$base.glstex") { rename "$base.glstex", "$path$base.glstex"; } # Analyze log file. local *LOG; $LOG = "$_[0].glg"; if (!$ret && -e $LOG) { open LOG, "<$LOG"; while () { if (/^Reading (.*\.bib)\s$/) { rdb_ensure_file( $rule, $1 ); } } close LOG; } return $ret; } ================================================ FILE: .vscode/extensions.json ================================================ { // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp // List of extensions which should be recommended for users of this workspace. "recommendations": [ "ms-vscode-remote.remote-containers", "James-Yu.latex-workshop" ], // List of extensions recommended by VS Code that should not be recommended for users of this workspace. "unwantedRecommendations": [] } ================================================ FILE: .vscode/settings.json ================================================ { "latex-workshop.latex.recipes": [ { "name": "latexmk", "tools": [ "latexmk" ] }, { "name": "lualatex", "tools": [ "lualatex" ] } ], "latex-workshop.latex.tools": [ { "name": "lualatex", "command": "lualatex", "args": [ "--shell-escape", "--synctex=1", "--recorder", "%DOC%" ] }, { "name": "latexmk", "command": "latexmk", "args": [ // latexmk doesn't need a file argument, but provide it to avoid running // on *all* found tex files "%DOC%" ] } ], "latex-workshop.latex.recipe.default": "first", "latex-workshop.linting.chktex.enabled": true, "latex-workshop.linting.run": "onSave", "latex-workshop.latex.autoBuild.run": "never", } ================================================ FILE: CHANGELOG.md ================================================ # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ## [5.0.0] - 2022-05-11 ### Added - GitHub Actions configuration (b847c85) This is supposed to replace the GitLab config. ### Changed - GitLab references to point to GitHub instead (7a33ee3) - Updated Python test suite from 3.7 to 3.10 (0733c83) - Simplified `polyglossia` language loading (053b87d) - Switched VSCode Remote Containers config from building to downloading image (4efd364). When new users first use this template, it is extremely frustrating for them to have to *build* the entire Docker image from scratch themselves, which can take very long. Simply download the existing one from DockerHub, which is much faster. ### Removed - GitLab-specific content (config files, documentation, ...) (7a33ee3) - Deprecated `chemmacros` `usechemmodule` macro (0909097) - Profanity check in PDF test (0733c83) ## [4.0.0] - 2021-10-18 ### Added - `matlab2tikz` improved alternative showcase using `pgfplots` (0910bca) - Important badges of high importance for important information (d19b8d9) - Hint on `parskip` usage to remove paragraph indentation in favor of vertical space (a292f6b) - Support for *Acronyms* glossary title localization (86c0be1) - New package for tables, `tabularray` (6825ff9, 480b400) - Docker image source (merged in c584129) - Additional math/unit font examples (2e3a582) ### Fixed - Display of dimensionless quantities (5f8dc71) - Tabular vertical excess white space (e5f983e) ### Changed - usage of `chemmacros` over `chemformula` (e379fa9, c26d613) - `siunitx` settings and usage to support [major version 3](https://github.com/josephwright/siunitx/blob/v3.0.0/CHANGELOG.md#v300) (bb931a9, 4fc2caf, 6747a36, 190bc89, e83902a, 82977ce) - Docker image source (b50eb6f, f10005e, 548dca9, a8fff45, afa8407, 3a0b4f0, a57a4ec) - massive simplification/moving of README content (f8f4d3f, 2925463, 2840312, a99df09, bcb4d69) ### Removed - LaTeX Workshop automatic compilation on save (6b0d313) - Old files (6fbdc2e, 04eb8fe, 096331c, b37316d, cdc285d) ## [3.1.0] - 2021-03-12 ### Added - Toggle for inclusion of glossaries in the Table of Contents (ToC) (5c23bd0) - Example for an appendix (d4a42ce) - Translations for code listings in references, lists, captions (6148d55) - ARCHITECTURE document (840eff8) - Example for a `longtabu` (multi-page table) displaying random data generated by custom Lua script (9e89214) - Section on alternative ways to compile (f2d550d) - Configuration and ideal setup for working with this template inside Visual Studio Code, using its native container development environment (38a0bb2) - Example for a new unit specification using `siunitx` (7a2d0d0) ### Changed - Switched bibliography generation from vanilla Zotero to Zotero with its excellent **Better Bibtex** addon (a05f5f4) - Fixed biblatex fields according to `biber --validate-datamodel` validation (eb068bd) - Fixed using a system directory for `pandoc`, which required `sudo` privileges (no just user privileges) (d8f4c1c) ### Removed - TeXGyrePagella font files: use those included in the TeX distribution itself (d74c2d9) - Trailing whitespaces (WOW!) (d766fb6) ## [3.0.0] - 2021-02-03 ### Added - Option to suppress printing of pages list in the glossaries (b75d3d1) - GitLab description templates (7038798) ### Changed - Syntax highlighting now uses `minted` instead of `listings`, a backwards-incompatible change (19fbd87) - Documentation now stresses Docker usage over manual "labour" (6843a2b) ### Removed - Previous, custom-made `listings` language definitions; these are covered much better by `pygments`, aka `minted` (19fbd87) ## [2.0.0] - 2020-11-11 ### Added - Python-based tests for the produced PDFs (1746e4e). This allows the user to automatically run a test suite against the produced PDFs, for example checking for page count, metadata and much more. - Makefiles for the [root](Makefile) and [tests](tests/Makefile) directories, while also swapping all CI routines over to use `make` (b4a9881). This allows for local as well as CI use using the same commands, and reduces coupling with the CI engine. - Caching of files in CI, for much faster pipelines (while introducing some issues) (28aea76). - Showcase and fixing of `\abs` macro for absolute values (4d0c6ff, bb11b72). ### Changed - Git metadata display in the colophon (7c59cbe). ## [1.2.0] - 2020-10-29 ### Added - Showcase for multiple lines with contours in TikZ overlay (ae4ad39) - Hint for the `glossaries-extra` *Beginner's Guide* (d8b7fb4) - Written permission (license) to use and distribute the [Fontin Sans](https://www.fontsquirrel.com/fonts/fontin-sans) font (cf79ee4) - Summary for font licenses (0372475) - Contributing guideline (56c4eac) - README info on git and Docker (fa228b7) - A `matlab2tikz` exported plot example (86dac19, c3e9b09) - `YAML`-based configs for pandoc (cb39706) - Proper check for the used TeX engine (de2a293) ### Changed - Fontawesome implementation, away from the `fontawesome` package to the more modern `fontawesome5` (8df784e) - Insertion of git metadata into the document (PDF metadata or into the printed text directly): now based on Lua (6d0cd7e) - Also adjusted the README according to the new Lua implementation (ed946b8) ## [1.1.1] - 2020-06-09 ### Added - Entry `Mach` in `names.bib` (d0d5683). Was previously removed, but is required. ## [1.1.0] - 2020-06-09 ### Added - Added `bib` file entries for the built-in math macros (f1803d3b): - `\mean` - `\logmean` - `\flow` - `\difference` - `\nablaoperator` - `\vect` - `\deriv` - `\fracderiv` - `\timederiv` - `\posderiv` - New tabular showcasing those built-in math macros (119fce11) - New tabular showcasing the built-in glossary commands (0e7ed5a9): - `\idx` - `\name` - `\sym` - `\sub` - `\abb` - `\cons` - Added sample entries for the *Terms* index (6ca2670b) ### Removed - Unused entry `Mach` in `names.bib` (c000d4ec) ## [1.0.0] - 2020-04-22 ### Added - Initial release ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2022 Alex Povel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ # This file contains instructions for the GNU `make` program: https://www.gnu.org/software/make/ # # The program is quite old, very stable, ubiquitous and widely used. # It is a staple in the Linux world. # There are ways to get it to run on Windows, but I haven't tried any. # Use WSL (https://docs.microsoft.com/en-us/windows/wsl/install-win10) instead and # save yourself the headaches. # `make` runs steps according to this very `Makefile` in order to arrive at a target, # like a PDF compiled with latex. # It checks all the dependencies automatically and only updates the target if changes # in the sources are detected. # The idea is that this project's PDFs can be compiled by simply calling e.g. # `make file.pdf` *both locally and in CI*. # Without make, we would otherwise have very different build steps in local and CI # environments. # Additionally, using `make`, the CI instructions (.gitlab-ci.yml, GitHub actions etc.) # can be simplified considerably, leading to decoupling. # Moving CI systems then becomes much easier. # ===================================================================================== # ===================================================================================== # Prerequisites # ===================================================================================== # ===================================================================================== # The following are "special targets", see: # https://www.gnu.org/software/make/manual/html_node/Special-Targets.html#Special-Targets # A phony target: not a file, just some routine. .PHONY: all clean mostlyclean clean-aux clean-pdf tex preflight help image # ===================================================================================== # Helper tool, adjusted from: # https://medium.com/@exustash/three-good-practices-for-better-ci-cd-makefiles-5b93452e4cc3 # Allows to annotate targets with regular comments and have a summary printed by calling # `make help`. # ===================================================================================== # Note escaping of comment char # FS = ":.*?\#" help: # List available targets on this project. First one shown is the default. @grep --extended-regexp --no-filename "\w+$(FS) .*" $(MAKEFILE_LIST) | \ awk --field-separator="$(FS)" '{printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' # ===================================================================================== # Set variables, executables and their flags. # ===================================================================================== # Common flags go here: # Configure latexmk tool using '.latexmkrc' in project root, not in here. LATEXMK_FLAGS = # For pandoc, provide dynamic metadata for the date (see below). Git short SHA works # both in CI and locally. All other settings are in the `defaults` file. PANDOC_FLAGS = --defaults=pandoc/defaults.yaml # Flags depending on CI/Local go here: # GitLab CI defines variables that we can check for. This allows us to detect if we're # in a CI scenario. # See also: # https://www.gnu.org/software/make/manual/html_node/Conditional-Syntax.html#Conditional-Syntax # https://docs.gitlab.com/ee/ci/variables/predefined_variables.html # # That same environment variable is defined for GitHub Actions as well: # https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables ifdef CI # In container, run commands directly: LATEXMK = latexmk PANDOC = pandoc # GIT_SHORT_SHA = $$CI_COMMIT_SHORT_SHA # pandoc is quiet by default PANDOC_FLAGS += --verbose # After the run, display the relevant rules (for debugging) LATEXMK_FLAGS += --rules else DOCKER_RUN = docker run --rm --volume ${PWD}:/tex DOCKER_IMAGE = alexpovel/latex # LATEXMK = $(DOCKER_RUN) --entrypoint="latexmk" $(DOCKER_IMAGE) PANDOC = $(DOCKER_RUN) --entrypoint="pandoc" $(DOCKER_IMAGE) # No supporting Docker image available yet: GIT_SHORT_SHA = $(shell git rev-parse --short HEAD) # latexmk is verbose by default: LATEXMK_FLAGS += --quiet endif PANDOC_FLAGS += --metadata=date:"$(shell date --iso-8601) ($(GIT_SHORT_SHA))" # ===================================================================================== # ===================================================================================== # Files to build # ===================================================================================== # ===================================================================================== # Produce all found tex files. tex_sources = $(wildcard *.tex) tex_pdfs := $(tex_sources:.tex=.pdf) # First rule is what is run by default if just using `make` with no arguments. # It is the 'goal': https://www.gnu.org/software/make/manual/html_node/Goals.html. # The name `all` is just a convention. # Change suffix of multiple different extensions (.tex, .md), to the same suffix (.pdf). # See also: https://stackoverflow.com/a/33926814 all: preflight tex README.pdf test # Performs preflight checks, then builds and tests all PDFs. # A rule for only LaTeX files: tex: $(tex_pdfs) # Builds all *.tex files into PDFs. # ===================================================================================== # Rules for file building # ===================================================================================== # This Makefile uses implicit rules, see: # https://www.gnu.org/software/make/manual/html_node/Implicit-Rules.html#Implicit-Rules # For those, Automatic Variables are important: # https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html # $*: "The stem with which an implicit rule matches" # $<: "The name of the first prerequisite" # $@: "The file name of the target of the rule" # $^: "The names of all the prerequisites, with spaces between them" # Pattern rule, see: # https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html, # Just sets up an implicit rule to specify how to get from prerequisite to target, # called whever `make` detects it needs to do so. No need to specify things manually. %.pdf: %.tex # Allows to build any PDF from a corresponding *.tex file. $(info Running $(LATEXMK) to build $@...) @$(LATEXMK) $(LATEXMK_FLAGS) $< PANDOC_TEMPLATE = $(strip $(shell grep "^template:" pandoc/defaults.yaml | cut --delimiter=":" --field=2)).latex PANDOC_TEMPLATE_DIR = ~/.pandoc/templates %.pdf: %.md $(PANDOC_TEMPLATE_DIR)/$(PANDOC_TEMPLATE) # Allows to build any PDF from a corresponding *.md file. $(info Running $(PANDOC) to build $@...) @$(PANDOC) $(PANDOC_FLAGS) --output=$@ $< EISVOGEL_ARCHIVE = Eisvogel.tar.gz EISVOGEL_VERSION = 3.4.0 # The `$(info ...)` function gives out-of-order logging, while `echo` works with the # `wget` progress display. $(PANDOC_TEMPLATE_DIR)/$(PANDOC_TEMPLATE): @echo "Template not found at $@, downloading..." @wget --quiet --show-progress --no-clobber \ "https://github.com/Wandmalfarbe/pandoc-latex-template/releases/download/v${EISVOGEL_VERSION}/${EISVOGEL_ARCHIVE}" @echo "Extracting $(EISVOGEL_ARCHIVE)..." @tar --extract --file=${EISVOGEL_ARCHIVE} Eisvogel-${EISVOGEL_VERSION}/eisvogel.latex # `$(@D)` is directory part of current target: @mkdir --parents $(@D) @mv "Eisvogel-${EISVOGEL_VERSION}/eisvogel.latex" $@ @$(RM) $(EISVOGEL_ARCHIVE) # ===================================================================================== # Help users install programs required for compilation and help debug. # ===================================================================================== preflight: # Performs checks to ensure prerequisites for compilation are met. @echo "Checking presence of required libraries..." @ldconfig --print-cache | grep --silent "librsvg" || \ (echo "librsvg missing: required by pandoc to convert files containing SVGs."; exit 69) @echo "Libraries OK." # Output looks like: https://tex.stackexchange.com/a/311753/120853 @$(LATEXMK) --commands # ===================================================================================== # Docker # ===================================================================================== image: ./.devcontainer/image/Dockerfile @docker build --tag alexpovel/latex:local --file $< . # ===================================================================================== # Testing. # ===================================================================================== include tests/Makefile # ===================================================================================== # Cleanup jobs. # ===================================================================================== clean-aux: # Cleans LaTeX's auxiliary files. @echo "Removing auxiliary files of all found TeX files..." @$(LATEXMK) -c $(LATEXMK_FLAGS) clean-pdf: # Cleans all found PDFs. @echo "Removing all PDF files:" @ls *.pdf 2>/dev/null || echo "No files to remove." @$(RM) *.pdf # For target name, see: https://www.gnu.org/prep/standards/html_node/Standard-Targets.html mostlyclean: clean-aux clean-pdf # Runs clean-{aux,pdf}, then cleans more. @echo "Removing downloaded pandoc archive, if any..." @$(RM) $(EISVOGEL_ARCHIVE) clean: mostlyclean # Runs all other clean jobs, then cleans absolutely everything. @echo "Removing all files ignored by git (.gitignore)..." @echo "For safety, this is done interactively:" @git clean -xd --interactive @echo "Removing pandoc template..." @$(RM) $(PANDOC_TEMPLATE_DIR)/$(PANDOC_TEMPLATE) ================================================ FILE: README.md ================================================ # LaTeX Cookbook [![Download PDF](https://img.shields.io/badge/Download-PDF-blue.svg)][download] This repo contains a [LaTeX document](cookbook.tex), usable as a cookbook (different "recipes" to achieve various things in LaTeX) as well as as a template. The resulting PDF covers LaTeX-specific topics and instructions on compiling the LaTeX source. See the [releases page](https://github.com/alexpovel/latex-cookbook/releases) for more downloads. > [!IMPORTANT] > This project is not archived, and [issues are still > addressed](https://github.com/alexpovel/latex-cookbook/issues/17). However, the > document is regarded as "done" and no new feature development actively happens. As LaTeX is a glacially slow-moving target, the document > should be useful, valid and buildable for many years to come still. > > There is a [fork > maintained](https://collaborating.tuhh.de/m21/public/theses/itt-latex-template) by > former coworkers of the author, at the research institute this template originated > from as well. Active development is still happening there. ## Getting started After installing [Docker](https://www.docker.com/) (and git), building works out of the box: - Bash: ```console $ git clone git@github.com:alexpovel/latex-cookbook.git $ cd latex-cookbook $ docker run --rm --volume $(pwd):/tex alexpovel/latex $ xdg-open cookbook.pdf ``` - PowerShell: ```powershell PS> git clone git@github.com:alexpovel/latex-cookbook.git PS> cd latex-cookbook PS> docker run --rm --volume ${PWD}:/tex alexpovel/latex PS> Invoke-Item cookbook.pdf ``` The [entrypoint](https://docs.docker.com/engine/reference/builder/#entrypoint) is [`latexmk`](https://ctan.org/pkg/latexmk?lang=en), which when given no arguments (as done here) runs on all found `*.tex` files, which in this case is only the root's [main file](./cookbook.tex). > [!NOTE] > Should this fail to compile (this is a bug, please report!), feel free to try other > images. When `alexpovel/latex` was built, > [`texlive/texlive`](https://hub.docker.com/r/texlive/texlive) did not exist yet. > **That image is strongly recommended**, as it is actively maintained by the actual > authors of TeXLive. If tools are missing, like `inkscape`, build your own image `FROM > texlive/texlive`, then install required software. > > Alternatively, there is [a > fork](https://collaborating.tuhh.de/m21/public/theses/latex_dockerfile) for the image > as well, accompanying the [template > fork](https://collaborating.tuhh.de/m21/public/theses/itt-latex-template). ## Features The [PDF itself][download] has much more to say on this and is meant to speak for itself, visually. The following is simply a brief overview of the features contained in this repo. ### Tooling - accompanying [Docker image](.devcontainer/image/Dockerfile), usable locally and in CI/CD, guaranteeing compilation success without interfering with your local installation. In fact, using Docker (containerization in general), no LaTeX installation is required at all. - accompanying Visual Studio Code [environment configuration](.devcontainer/devcontainer.json). If you open this repository in [Visual Studio Code](https://code.visualstudio.com/), it should automatically put you into the correct Docker container environment for development, and just work™. See [here](.devcontainer/README.md) for more info. - in the image, [`pandoc`](https://pandoc.org/) is available with the [Eisvogel](https://github.com/Wandmalfarbe/pandoc-latex-template) template, allowing beautiful PDFs to be generated from Markdown (like this README: download it from the latest [Actions artifacts](https://github.com/alexpovel/latex-cookbook/actions); it currently looks lackluster because this README is mainly PNGs) - [tests](tests/config.yml) for your PDF, using Python to ensure some (basic) properties of your output adhere to expectations - a [Makefile](Makefile) to facilitate ease of use and platform independence (commands like `make file.pdf` work locally as well as in CI pipelines) ### LaTeX-specific - full Unicode support through `lualatex`, the [successor](https://en.wikipedia.org/wiki/LuaTeX) to the obsolete `pdflatex`. This also affords beautiful font typesetting through [`unicode-math`](https://ctan.org/pkg/unicode-math). High-quality fonts like [TeX Gyre Pagella](https://ctan.org/pkg/tex-gyre-pagella) have all desirable font shapes available: ![font-shapes](images/bitmaps/readme/font-shapes.png) - automatic compilation using [`latexmk`](.latexmkrc), ensuring the PDF is built fully, running all steps necessary (generation of the bibliography, glossaries, ...) automatically as needed - comprehensive support for: - generating [indices](bib/glossaries/index/), - typesetting and displaying [symbols](bib/glossaries/symbols/) in an automatically generated nomenclature, - [acronyms and abbreviations](bib/glossaries/abbreviations.bib), as well as - [mathematical constants](bib/glossaries/constants.bib), made possible through [`glossaries-extra`](https://ctan.org/pkg/glossaries-extra). - structured and commented source code, explaining rationales and providing context - showcasing plotting and data display (floats): - computing more complicated plots (in this example, a contour plot) *directly in LaTeX*, with no explicit outside tools used ([`gnuplot`](http://www.gnuplot.info/) is used by LaTeX in the background): ![plot-compute](images/bitmaps/readme/plot-compute.png) - ingesting a CSV directly, and plotting it (so we can skip [`matlab2tikz`](https://www.mathworks.com/matlabcentral/fileexchange/22022-matlab2tikz-matlab2tikz) etc.). The below style is inspired by [Tufte](https://www.edwardtufte.com/tufte/): ![plot-csv](images/bitmaps/readme/plot-csv.png) - typesetting more complex tables, with footnotes, decimal alignment and more: ![table](images/bitmaps/readme/tables.png) - using tikz: - for annotating bitmap graphics: ![tikz-annotation](images/bitmaps/readme/tikz-annotations.png) - for drawing diagrams (this template contains a (basic) `pgf`/`tikz` library for energy systems/thermodynamics/hydraulics/... symbols like pipes, compressors, valves, ...) and 3D sketches. For a much better and comprehensive collection of TikZ examples, see [here](https://texample.net/tikz/examples/). ![tikz-diagram](images/bitmaps/readme/tikz-diagram.png) ![tikz-libaries](images/bitmaps/readme/tikz-libraries.png) - back-referencing of citations, using the excellent [`biblatex`](https://ctan.org/pkg/biblatex): ![backref](images/bitmaps/readme/backref.png) - support for elaborate chemical reaction equations, using [`chemmacros`](https://ctan.org/pkg/chemmacros): ![chemmacros](images/bitmaps/readme/chem.png) - comprehensive code syntax highlighting, thanks to [`minted`](https://ctan.org/pkg/minted) and `pygments`: ![pygments](images/bitmaps/readme/code.png) - quick and structural switching of language contexts, provided by [`polyglossia`](https://ctan.org/pkg/polyglossia): ![language](images/bitmaps/readme/language.png) - of course, support for enhanced mathematical typesetting, like highlighted equations or premade macros. The blue color are *hyperlinks*, turning those symbols into links to the glossary (this can be toggled off). ![math](images/bitmaps/readme/math.png) ![math-macros](images/bitmaps/readme/math-macros.png) [download]: https://github.com/alexpovel/latex-cookbook/releases/latest/download/cookbook.pdf ================================================ FILE: acp.cls ================================================ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % LuaLaTeX based on KOMA-Script % % Author (2021): Alex Povel - tex(at)alexpovel.de %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Class Options %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Refer to https://www.overleaf.com/learn/latex/Writing_your_own_class \NeedsTeXFormat{LaTeX2e} \ProvidesClass{acp}[2021-10-06 v4.0.0 acp class] % Fail early and give useful information on the required engine. % This helps users who do not read the documentation beforehand, by promoting the % requirement from some statement in the docs to actual code that errors out. \RequirePackage{iftex} \RequireLuaTeX{} \newcommand*{\@baseclass}{scrbook}% Name of class this one is based on % If option 'language' is not given at all, use initialization 'english' as a fallback. % If it is called without a value, use default (or throw error of no default given) % This method was chosen to have the language available in a macro, so it may be passed % to polyglossia. % This approach messes with the forwarding of the language and raises a warning % 'Unused global options'; we can probably ignore that for now % (https://tex.stackexchange.com/a/278172/120853). \RequirePackage{kvoptions} %[default]{language} % If no default entered: option requires a value: \DeclareStringOption[english]{language} \DeclareStringOption{titlestyle} \DeclareBoolOption{censoring}% Initially false by default \ProcessKeyvalOptions* \PassOptionsToClass{% \acp@language,% Scheme: \filename@keyoption twoside,% For printing two-sided documents % 'List of (Tables, Figures, ...)' gets pushed down one hierarchical level: % listof=leveldown, listof=totoc,% All registered Lists of XYZ to Table of Contents bibliography=totoc, chapterprefix=true,% Print 'Chapter' etc. label in front of number open=right,% Open new Chapters on recto pages numbers=noenddot,% https://tex.stackexchange.com/a/102305/120853 }{\@baseclass} % Bundle 'a5' to not only have a5paper but also decrease font size. % https://tex.stackexchange.com/a/418947/120853 % https://tex.stackexchange.com/a/27149/120853 \DeclareOption{a5}{% % Not forwarded to typearea package if passed as class option: do it manually here: \PassOptionsToPackage{paper=a5}{typearea} \PassOptionsToClass{fontsize=10pt}{\@baseclass}% }% % Forward all other options given to \documentclass[] to base class: \DeclareOption*{\PassOptionsToClass{\CurrentOption}{\@baseclass}} \ProcessOptions\relax% Execute these options \LoadClass{\@baseclass}% Finally, load the base class \RequirePackage[\acp@language]{tracklang}% Language Tracking %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Typography and Misc. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{scrhack}% Fixes for packages incompatible with KOMA features \RequirePackage{import}% Relative path imports \RequirePackage[super]{nth}% For ordinal numbers, like \nth{1} -> 1^{st} \RequirePackage{etoolbox}% Programming facilities %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Translations %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Providing localization that are not automatically covered by polyglossia. % The commands are provided by KOMAscript. % Maintaining the list is not the easiest, but currently likely the best approach. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Colophon %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \providecaptionname{english}{\TransCompiledOn}{Compiled on} \providecaptionname{german}{\TransCompiledOn}{Kompiliert am} \providecaptionname{english}{\TransLatexClass}{Class} \providecaptionname{german}{\TransLatexClass}{Klasse} \providecaptionname{english}{\TransGenerator}{Generator} \providecaptionname{german}{\TransGenerator}{Generiert durch} \providecaptionname{english}{\TransCensorNotice}{CENSORED VERSION} \providecaptionname{german}{\TransCensorNotice}{ZENSIERTE VERSION} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Task %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \providecaptionname{english}{\TransPlaceDate}{Place \& Date} \providecaptionname{german}{\TransPlaceDate}{Ort \& Datum} \providecaptionname{english}{\TransTopic}{Topic} \providecaptionname{german}{\TransTopic}{Thema} \providecaptionname{english}{\TransTask}{Task} \providecaptionname{german}{\TransTask}{Problemstellung} \providecaptionname{english}{\TransFor}{For} \providecaptionname{german}{\TransFor}{Für} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Declaration of Authorship %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \providecaptionname{english}{\TransAuthorshipDeclTitle}{Declaration of Authorship} \providecaptionname{german}{\TransAuthorshipDeclTitle}{Erklärung zur Eigenständigkeit} % % No warranty these wordings are valid in your case! % \providecaptionname{english}{\TransAuthorshipDeclText}{% I, \@author{}, hereby declare to be the sole, independent author of the \@documenttype{} submitted here. No other than the cited references have been used. Any content directly or indirectly obtained from external sources has been marked up as such. This thesis has neither been submitted to a second examination authority nor been published.% }% \providecaptionname{german}{\TransAuthorshipDeclText}{% Hiermit bestätige ich, \@author{}, der alleinige und selbstständige Autor der hier vorgelegten \@documenttype{} zu sein. Keine anderen als die angegebenen Quellen wurden benutzt. Jeglicher aus externen Quellen direkt oder indirekt bezogene Inhalt ist als solcher markiert. Diese Arbeit wurde weder einer anderen Prüfungsbehörde vorgelegt noch veröffentlicht. }% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Cleveref %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \providecaptionname{english}{\TransReaction}{Reaction} \providecaptionname{german}{\TransReaction}{Reaktion} \providecaptionname{english}{\TransReactions}{Reactions} \providecaptionname{german}{\TransReactions}{Reaktionen} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Glossary %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \providecaptionname{english}{\TransGreek}{Greek} \providecaptionname{german}{\TransGreek}{Griech.} \providecaptionname{english}{\TransRoman}{Roman} \providecaptionname{german}{\TransRoman}{Röm.} \providecaptionname{english}{\TransOther}{Other} \providecaptionname{german}{\TransOther}{Andere} \providecaptionname{english}{\TransTerms}{Terms} \providecaptionname{german}{\TransTerms}{Begriffe} \providecaptionname{english}{\TransNames}{Names} \providecaptionname{german}{\TransNames}{Namen} \providecaptionname{english}{\TransAcronyms}{Acronyms} \providecaptionname{german}{\TransAcronyms}{Akronyme} \providecaptionname{english}{\TransSubscripts}{Subscripts} \providecaptionname{german}{\TransSubscripts}{Indizes} \providecaptionname{english}{\TransSuperscripts}{Superscripts} \providecaptionname{german}{\TransSuperscripts}{Hochgest.} \providecaptionname{english}{\TransSubSuperTitle}{Sub- and Superscripts} \providecaptionname{german}{\TransSubSuperTitle}{Indizes} \providecaptionname{english}{\TransUnit}{Unit} \providecaptionname{german}{\TransUnit}{Einheit} \providecaptionname{english}{\TransPhysicalQuantity}{Phys.\ Qtt.} \providecaptionname{german}{\TransPhysicalUnit}{Phys.\ Größe} \providecaptionname{english}{\TransFirstUse}{\nth{1} Use} \providecaptionname{german}{\TransFirstUse}{Einführ.} \providecaptionname{english}{\TransShort}{Short} \providecaptionname{german}{\TransShort}{Kurz} \providecaptionname{english}{\TransContinued}{continued} \providecaptionname{german}{\TransContinued}{fortgesetzt} \providecaptionname{english}{\TransGlossaryLegend}{ Marked (\specificsymbolmark) symbols possess a mass\-/specific variant in which the symbol is written in lowercase and the unit is extended by \unit[per-mode=reciprocal]{\per\kilogram}. Alternative symbols are specified following the \alternativesymbolmark{} mark. International symbols are specified in brackets.% } \providecaptionname{german}{\TransGlossaryLegend}{ Markierte (\specificsymbolmark) Symbole besitzen eine massenspezifische Variante, bei der das Symbol als Kleinbuchstabe gesetzt und die Einheit entsprechend um \unit[per-mode=reciprocal]{\per\kilogram} erweitert wird. Alternative Symbole sind nach \alternativesymbolmark{} angegeben, internationale Symbole in eckigen Klammern.% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SCRLayer %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \providecaptionname{english}{\TransBlankPage}{Rest of this page intentionally left blank.} \providecaptionname{german}{\TransBlankPage}{Rest der Seite absichtlich freigelassen.} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Lists of ... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \providecaptionname{english}{\TransIllustrativeElements}{Illustrative Elements} \providecaptionname{german}{\TransIllustrativeElements}{Veranschaulichende Elemente} \providecaptionname{english}{\TransListOfIllustrations}{List of Illustrations} \providecaptionname{german}{\TransListOfIllustrations}{Illustrationsverzeichnis} \providecaptionname{english}{\TransListing}{Code Listing} \providecaptionname{english}{\TransListings}{Code Listings}% Plural for cleveref \providecaptionname{german}{\TransListing}{Code} \providecaptionname{german}{\TransListings}{Codes}% Plural for cleveref \providecaptionname{english}{\TransListOfListings}{List of Code} \providecaptionname{german}{\TransListOfListings}{Codeverzeichnis} \providecaptionname{english}{\TransListOfExamples}{List of Examples} \providecaptionname{german}{\TransListOfExamples}{Beispielverzeichnis} \providecaptionname{english}{\TransExample}{Example} \providecaptionname{german}{\TransExample}{Beispiel} \providecaptionname{english}{\TransExamples}{Examples} \providecaptionname{german}{\TransExamples}{Beispiele} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Bibliography %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \providecaptionname{english}{\TransFurtherReadingTitle}{Further Reading} \providecaptionname{german}{\TransFurtherReadingTitle}{Weitere Literatur} \providecaptionname{english}{\TransFurtherReadingText}{% The following references were used in this work but not cited in the text body; they are provided here as\-/is. } \providecaptionname{german}{\TransFurtherReadingText}{% Die folgenden Quellen wurden im Rahmen dieser Arbeit benutzt, jedoch nicht explizit zitiert. Sie sind hier der Vollständigkeit halber aufgeführt. } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Other %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \providecaptionname{english}{\TransConstant}{const} \providecaptionname{german}{\TransConstant}{konst} \providecaptionname{english}{\TransAdaptedFrom}{Adapted from} \providecaptionname{german}{\TransAdaptedFrom}{Adaptiert von} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Tweaks and improvements for amsmath; also loads amsmath. % Needs to be loaded before unicode-math! \RequirePackage{mathtools} % We want to be cool, so standard parantheses don't cut it: \newtagform{brackets}{[}{]} \usetagform{brackets} % Allow multi-line environments to break across pages. % While it makes sense to disallow it, not doing so can produce big spacing issues. % Usually, any such environment will require manual attention. % Number from 1 to 4 as optional argument: % [1]: allow pagebreaks, but avoid as much as possible. % [4]: maximum permissiveness \allowdisplaybreaks[2] % Automatic macro for delimiters (parentheses, brackets, ...) % Using the starred variant of the created command (like \parens*{}) % also scales the delimiters automatically, using \left and \right. \DeclarePairedDelimiter{\parens}{(}{)} \DeclarePairedDelimiter{\brackets}{[}{]} \DeclarePairedDelimiter{\braces}{\{}{\}} % For a 'cases' environment that also supports equation numbering, % https://tex.stackexchange.com/a/180910/120853 \RequirePackage{empheq} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Colour %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Load this before unicode-math font specifications to make colors available there \RequirePackage[x11names]{xcolor}% x11names provides some usable default names % Shades of grey (we don't need 50 though) % This is nice to have consistent color shading. \colorlet{g1}{black!70} \colorlet{g2}{black!55} \colorlet{g3}{black!40} \colorlet{g4}{black!20} \colorlet{g5}{black!10} \colorlet{g6}{black!05} % Different fluids/materials. \definecolor{Glass}{RGB}{170, 238, 255}% Very light blue \definecolor{Air}{RGB}{213, 246, 255}% Light blue \definecolor{LightFluid}{RGB}{148, 224, 255} \definecolor{MediumFluid}{RGB}{135, 178, 232} \definecolor{DarkFluid}{RGB}{119, 151, 197} \definecolor{HotFluid}{RGB}{255, 128, 128}% 255/128/128 is same as 'red!50' % Dark blue link color: \definecolor{darklink}{RGB}{48, 62, 116}% % From colorbrewer's RdYlBu: from red (1) to blue (6) \definecolor{rdylbu1}{RGB}{215, 48, 39}% \definecolor{rdylbu2}{RGB}{252, 141, 89}% \definecolor{rdylbu3}{RGB}{254, 224, 144}% \definecolor{rdylbu4}{RGB}{224, 243, 248}% \definecolor{rdylbu5}{RGB}{145, 191, 219}% \definecolor{rdylbu6}{RGB}{ 69, 117, 180}% % From colorbrewer's Set2 for qualitative data/color discernibility \definecolor{Set2A}{RGB}{102, 194, 165}% \definecolor{Set2B}{RGB}{252, 141, 98}% \definecolor{Set2C}{RGB}{141, 160, 203}% \definecolor{Set2D}{RGB}{231, 138, 195}% \definecolor{Set2E}{RGB}{166, 216, 84}% \definecolor{Set2F}{RGB}{255, 217, 47}% \definecolor{Set2G}{RGB}{229, 196, 148}% \definecolor{Set2H}{RGB}{179, 179, 179}% % Matlab colours: \definecolor{mBlue}{HTML}{0072BD} \definecolor{mOrange}{HTML}{D95319} \definecolor{mYellow}{HTML}{EDB120} \definecolor{mPurple}{HTML}{7E2F8E} \definecolor{mGreen}{HTML}{77AC30} \definecolor{mSky}{HTML}{4DBEEE} \definecolor{mRed}{HTML}{A2142F} % Code annotations: \definecolor{cRed}{RGB}{209,0,86}% \definecolor{cBlue}{RGB}{0, 130, 185}% \definecolor{cGreen}{RGB}{0, 128, 63}% \definecolor{cOrange}{RGB}{244, 131, 66}% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Typeset code snippets %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % minted is a Python-based syntax highlighter and therefore much, much more powerful % than anything LaTeX-built-in \RequirePackage[% % `minted` uses the `float` package to provide the `[H]` float position specifier. % Sadly, the `float` package is incompatible with `floatrow`, which we make heavy % use of. Luckily, we can use `minted` with the `newfloat` package instead, fixing % all those otherwise breaking issues. % See https://tex.stackexchange.com/a/378588/120853 newfloat=true,% ]{minted} \setminted{% Global `minted` aka code syntax highlighting options % If code is indented in the LaTeX source, this is reflected in the print. % This option automatically removes as much whitespace as the first line of a listing % is indented by (note: requires `python` to be available, not only `pygmentize`) autogobble=true, % % Assuming the code to be displayed is written at 80-90 characters per line, % \footnotesize makes sure it fits onto one line (roughly). fontsize=\footnotesize, % breaklines=true, breakanywhere=false, % default "false"; could be ugly, only use if required breakbytokenanywhere=true, % Breaks tokens on non-spaces too % % Regular LaTeX can occur in these (on UK Keyboard: SHIFT+`). % Otherwise, you'll have to copy-paste this whenever needed. % The problem is that the escapechar has to be quite exotic so it never occurs % in source code. escapeinside=¬¬, % frame=leftline, % leftline pulls it together visually quite nicely framerule=1pt, % default is 0.4pt rulecolor=\color{g3}, % numbers=left, numberfirstline=true, % Always color the first line despite `stepnumber` setting stepnumber=5, % Interval of line numbering numbersep=2pt, % Horizontal distance between line number and line % % Used highlighting style, see https://pygments.org/demo/#try or `python -m pygments -L` % For colorful output, I like: % `paraiso-light` (prob. too light for print), `manni`, `tango`, `lovelace` % For grayscale: % `algol` style=manni, } \setmintedinline{% Overwrite `\setminted` settings fontsize=auto,% Reset to surrounding font size so its fits into the text flow } % Set up the floating environment, e.g. what is says in the caption of floats: \SetupFloatingEnvironment{listing}{% Requires `newfloat` usage name=\TransListing{}, listname=\TransListOfListings{}, } % Create a new environment for breaking code listings across pages. \newenvironment{longlisting}{\captionsetup{type=listing}}{} % Setup for referencing the floats correctly is done in `cleveref` settings! % In code environments, to be able to copy from the PDF (despite that not being a good % idea usually), we want the line numbers to not be part of the selection. % This command prints them, but renders the actual copied content empty, % on supported readers like Adobe Acrobat. \RequirePackage{accsupp}% https://tex.stackexchange.com/a/57160/120853 \newcommand*{\emptyaccsupp}[1]{% \BeginAccSupp{ActualText={}}#1\EndAccSupp{}% }% \renewcommand*{\theFancyVerbLine}{ % Redefine how line numbers are printed \textcolor{g3}{\ttfamily\tiny\emptyaccsupp{\arabic{FancyVerbLine}}} } % Colors for escaped, normal LaTeX in code environments \newcommand*{\phstring}[1]{% \textcolor{cRed}{#1}% }% \newcommand*{\phnum}[1]{% \textcolor{cBlue}{#1}% }% \newcommand*{\phother}[1]{% \textcolor{cGreen}{#1}% }% \newcommand*{\phnote}[1]{% {% \hypersetup{allcolors=cOrange}% If references occur in here \textbf{\textcolor{cOrange}{#1}}% }% }% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % TODO notes in the PDF %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{todonotes}% TODO-notes in the margins \setuptodonotes{fancyline}% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Fonts %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage[ warnings-off={ % Unicode overwrites colon-commands but uses over/underbracket from mathtools % and warns us; suppress this: mathtools-colon,% mathtools-overbracket,% } ]{unicode-math}% Builds onto fontspec and loads it automatically %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Fonts shipped with TeXLive from here: https://tug.org/FontCatalogue/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \setmainfont[% Numbers=Lowercase,% Hanging/OldStyle numbers through Lowercase numbers % Color=Orange2,% Toggle color for debugging (should be xcolor name) ]{TeX Gyre Pagella}% Load existing fond, see also https://tex.stackexchange.com/a/351100/120853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Source: https://fonts.google.com/specimen/Inconsolata % (Consolas is considered better but is not free (?)) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \setmonofont[% % Inconsolata doesn't have italics font, so fake it. Discouraged but should % only occur in a few places in code and not be noticable there. Inconsolata % is too nice to give up on it for lack of italics. See also % https://tex.stackexchange.com/a/183220/120853 AutoFakeSlant, Scale=MatchLowercase,% Prettier when using inline-code alongside our main font % Color=DodgerBlue3,% Toggle color for debugging (should be xcolor name) ]{inconsolata}% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Source: https://www.exljbris.com/fontinsans.html % Viable alternative: https://fonts.google.com/specimen/Fira+Sans %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \setsansfont[% % Color=Red3,% Toggle color for debugging (should be xcolor name) ]{Merriweather Sans}% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Source: https://ctan.org/texarchive/fonts/tex-gyre-math/opentype %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \setmathfont[% %Set math-font-commands to new versions; use \symbf{} instead of \mathbf{} etc: mathrm=sym,% mathit=sym,% mathsf=sym,% mathbf=sym,% mathtt=sym,% % 'tpgl': 'TexGyrePagellaLining'. % This 'NFSS' style is required for \fontfamily{nfss-code}\selectfont to work, % e.g. in package chemmacros/chemformula NFSSFamily=tgpl,% % Color=Green4,% Toggle color for debugging (should be xcolor name) ]{TeX Gyre Pagella Math}% Load existing fond, see also https://tex.stackexchange.com/a/351100/120853 % Provide a new font family for siunitx to work. % See: https://tex.stackexchange.com/a/468031/120853. % \newfontfamily is used similarly to \setmainfont etc, % see: https://tex.stackexchange.com/a/12568/120853 \newfontfamily{\unitnumberfont}[ % New font family for typesetting units. % Required since otherwise, numbers typeset with \qty/\num etc. from siunitx % might be hanging if that feature is turned on in the main font (OldStyle numbers). % To ensure these physical numbers are always upright, set Numbers: Numbers=Uppercase, % Color=LightCyan4,% Toggle color for debugging (should be xcolor name) ]{TeX Gyre Pagella}% Load existing fond, see also https://tex.stackexchange.com/a/351100/120853 % Looking at CTAN, `fontawesome5' looks much more recent and packs many more symbols % in comparison to `fontawesome'. % It ships with its own font files, so no need to specify here. \RequirePackage{fontawesome5}% High-quality Unicode vector web symbols % Wrapper for "i.e.", "e.g.", "c.f.", "etc.", etc. % Call this command as "The animals, \iecfeg{e.g.}\ an elephant, are..." % to get a small space after the ending period. % We do not define dedicated commands here (like \eg or \etc) to print that stuff % automatically, since there are way too many exceptions and caveats. % Such macros are not worth it because the requirements change too much from use to use % (different languages, capitalisation, ending dot if abbreviation is at end of % sentence, ...). % It is left to the user to do the specifics. % This macro just makes sure it is all in italics. \newcommand*{\iecfeg}[1]{\textit{#1}}% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % System Information Banner %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Provides \hologo and \Hologo to typeset various logos, like the LuaLaTeX logo. \RequirePackage{hologo} % Using fontspec, this document is incompatible with anything but XeLaTeX/LuaLaTeX. % LuaLaTeX can grab additional memory as needed, therefore no issues with tikz and no % need to tikzexternalize (!). % Further, contour-package and XeLaTeX are strictly incompatible (LuaLaTeX works). % Therefore, only ever use LuaLaTeX anyway. \RequirePackage{xstring}% String manipulation macros % Print only what occurs after 'This is ' and store in macro given in brackets at end. % luatexbanner is provided by luatex engine, but prints 'This is luatex XYX' usually. % https://tex.stackexchange.com/a/394043/120853 \StrBehind*{\luatexbanner}{This is }[\shortbanner] % Take input and substitute strings; here: make plain LuaTeX string into pretty logo. % StrSubstitue has no starred variant, therefore dekotenize. % https://tex.stackexchange.com/a/350583/120853 \StrSubstitute{\shortbanner}{\detokenize{LuaTeX}}{\hologo{LuaTeX}}[\prettybanner] % Generate some control sequences which contain metadata, which can be inserted e.g. % into the PDF metadata (e.g. to have the exact git commit SHA of a build). % See % https://www.overleaf.com/learn/latex/Articles/An_Introduction_to_LuaTeX_(Part_2):_Understanding_%5Cdirectlua % for how to inline Lua code in TeX. % It's an absolute abomination; the below code first passes through TeX, gets expanded, % then gets processed by Lua. % Hence, there is a lot of escaping going on. \directlua{% local function get_cmd_stdout(cmd) % -- See: https://stackoverflow.com/a/326715/11477374 local fh = assert(io.popen(cmd)) local first_line = assert(fh:read()) fh:close() return first_line end % % -- Environment variables as used e.g. in GitLab CI. % -- Otherwise, e.g. when developing locally, use commands as a fallback. local macro_content_sources = { GitRefName = { env = "CI_COMMIT_REF_NAME", cmd = "git rev-parse --abbrev-ref HEAD", }, GitShortSHA = { env = "CI_COMMIT_SHORT_SHA", cmd = "git rev-parse --short HEAD", }, } % for macro_name, content_sources in pairs(macro_content_sources) do % -- Default: check for environment variable: local env = content_sources.env local cmd = content_sources.cmd % -- Default value: local content = "n.a." local env_content = os.getenv(env) % % -- Empty string evaluates to true: if env_content and env_content \noexpand~= "" then texio.write_nl("Found and will be using environment variable '"..env.."'.") content = env_content else texio.write_nl("Environment variable '"..env.."' undefined or empty, trying fallback command.") % -- luatex reference for shell escape: % -- "0 means disabled, 1 means anything is permitted, and 2 is restricted" if status.shell_escape == 1 then local cmd_success, cmd_stdout = pcall(get_cmd_stdout, cmd) if cmd_success then texio.write_nl("Fallback command '"..cmd.."' succeeded.") content = cmd_stdout else texio.write_nl("Fallback command '"..cmd.."' unsuccessful.") end else texio.write_nl("shell-escape is disabled, cannot use fallback command.") end end % % -- Shouldn't happen, would be programmer error, therefore assert Python-style assert(content, "Content not defined (neither success nor fallback present)") % % --[[ % The `content` can contain unprintable characters, like underscores in git branch % names. Towards this end, use detokenize in the macro itself, which will make all % characters printable (assigns category code 12). See also: % https://www.overleaf.com/learn/latex/Articles/An_Introduction_to_LuaTeX_(Part_2):_Understanding_%5Cdirectlua % --]] local escaped_content = "\unexpanded{\\detokenize{"..content.."}"} % texio.write_nl("Providing new macro '"..macro_name.."' with contents: '"..escaped_content.."'.") % -- Set a macro (newcommand) see also: https://tex.stackexchange.com/a/450892/120853 token.set_macro(macro_name, escaped_content) end } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Macros to pretty-print keyboard buttons and menu navigation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage[ os=win,% Default is `mac` ]{menukeys} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % KOMA Layout, Sectioning etc %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % label, e.g. 'Chapter', appearing before the chapter number: \addtokomafont{chapterprefix}{\raggedleft} \renewcommand*{\chapterformat}{% \color{g3}% g3 is a shade of grey % % chapappifchapterprefix{addtext} checks if 'chapterprefix=true' is active, % then prints 'Chapter' or 'Appendix' in front of number, % followed by more text 'addtext': \chapappifchapterprefix{~}% ~ is an unbreakable space character % % Autodot automates the generation of a dot/period, like \thechapter\autodot. % Leave out for no dot. \scalebox{4.5}{\thechapter} }% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Titlepage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Define new font for the title page, so it is created once (\newkomafont) % and can later be set however often required (\setkomafont) \newkomafont{documenttype}{\usekomafont{subtitle}\footnotesize} % Emulating a budget 'case' switch statement here % \ifstrequal from etoolbox doesn't work, it does not expand macros. % Use \ifdefstring from same package, % see also https://tex.stackexchange.com/a/451937/120853 \ifdefstring{\acp@titlestyle}{thesis}{ % These exist already, overwrite: \setkomafont{title}{\sffamily\bfseries\Huge} \setkomafont{subtitle}{\normalfont\normalsize\sffamily} \setkomafont{author}{\sffamily\bfseries} \setkomafont{publishers}{\sffamily} % % One same line as subtitle, so should look the same; inherit style: \setkomafont{date}{\usekomafont{subtitle}} % \setkomafont{documenttype}{\usekomafont{subtitle}\footnotesize} % \renewcommand{\maketitle}{% \begin{titlepage} \hfill% % % 2nd optional argument is height, required for \vfill etc. to work \begin{minipage}[b][1\textheight]{0.05\textwidth}% \color{black}\rule{0.15em}{\textheight}% Vertical line \hfill% \end{minipage}% This comment char is important to suppress linebreak % \begin{minipage}[b][1\textheight]{0.75\textwidth} \vspace{4\baselineskip} {\usekomafont{documenttype}\faGraduationCap{}\ \@documenttype{}\hspace{0.5em}} \hrulefill \begin{spacing}{1.1}% In case of multi-line titles, more relaxed spacing \usekomafont{title}\raggedright\@title \end{spacing} \hrule \vspace{0.8\baselineskip} {% \usekomafont{author}% % Tabular enables \and and \\ syntax \begin{tabular}[t]{@{}l@{}}% \@author \end{tabular} }% \hfill {\usekomafont{date}\@date}\par \vfill {\usekomafont{subtitle}\@subtitle}\par \vspace{2\baselineskip} {% \usekomafont{publishers}% \begin{tabular}[t]{@{}l@{}}% \@publishers \end{tabular} }\par \vspace{0.2ex}% Also required for \vfill as something to 'fill against' \end{minipage} \end{titlepage} }% }{% % Else: nothing; faking a 'case' environment } \ifdefstring{\acp@titlestyle}{book}{ % These exist already, overwrite: \setkomafont{title}{\sffamily\bfseries\Huge} \setkomafont{subtitle}{\itshape} \setkomafont{author}{\scshape\Large} \setkomafont{date}{\normalfont\normalsize\sffamily} \setkomafont{publishers}{\scshape} % % One same line as date, so should look the same; inherit style: \setkomafont{documenttype}{\usekomafont{date}} % \renewcommand{\maketitle}{% \begin{titlepage} \hfill% % % 2nd optional argument is height, required for \vfill etc. to work \begin{minipage}[b][1\textheight]{0.05\textwidth}% \color{black}\rule{0.15em}{\textheight}% Vertical line \hfill% \end{minipage}% This comment char is important to suppress linebreak % \begin{minipage}[b][1\textheight]{0.75\textwidth} \vspace{2\baselineskip} {\usekomafont{author} % Tabular enables \and and \\ syntax \begin{tabular}[t]{@{}l@{}}% \@author \end{tabular} }\par \vspace{1.5\baselineskip} \begin{spacing}{1.1}% In case of multi-line titles, more relaxed spacing \usekomafont{title}\raggedright\@title \end{spacing} \hrule \vspace{0.8\baselineskip} {\usekomafont{documenttype}\@subtitle} \hfill {\usekomafont{date}\@date}\par \vfill {\usekomafont{publishers} \begin{tabular}[t]{@{}l@{}}% \@publishers \end{tabular} }\par \vspace{0.2ex}% Also required for \vfill as something to 'fill against' \end{minipage} \end{titlepage} }% }{ % Else: nothing; faking a 'case' environment }% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % tocbasic %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Dynamic width of number column in LoF/LoT etc (numsep + width of longest entry). % 'tocline' is the (dynamic) default style. \DeclareTOCStyleEntry[dynnumwidth=true]{tocline}{figure} \DeclareTOCStyleEntry[dynnumwidth=true]{tocline}{table} % Declare a new list of contents, with the file suffix in brackets. % This will give access to \listofs \DeclareNewTOC[% type=example,% This also creates types=example+s, that is by appending an s % Listname is "List of s" by default, therefore translate: listname={\TransListOfExamples{}}, ]{loe} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % SCRLayer for page makeup (header/footer etc.) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage[automark]{scrlayer-scrpage}% Automatically mark \clearpairofpagestyles % Reset defaults % Declare new length (acting as a height) for the vertical bar in the header: \newlength{\headerrulelength} % Increase height of rule here; KOMA Script will complain, no idea how to fix \setlength{\headerrulelength}{3ex} % New command for the vertical rule, with height as specified by the new length above: \newcommand*{\headerrule}{% \rule[-1ex]{0.1em}{\headerrulelength}% }% % Define headers: \lehead{% Left, even head \llap{% \pagemark\enskip\headerrule% }% \enskip\headmark% }% \rohead{% Right, odd head \headmark\enskip% \rlap{% \headerrule\enskip\pagemark% }% }% % https://tex.stackexchange.com/q/299125/120853: \renewcommand*{\chaptermarkformat}{\thechapter\enskip}% \addtokomafont{pagehead}{\sffamily\itshape\footnotesize}% \addtokomafont{pagenumber}{\sffamily\bfseries\footnotesize}% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Deliberately blank pages with message % Occurs if new chapter starts (opens right) but previous chapter ended on % a recto (right) page itself. % The intermediate left page will be blank; leave a message that this is intentional. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newcommand*{\blankpage}{% https://tex.stackexchange.com/a/205536/120853 \par\vspace*{\fill}% \begin{center} \textcolor{g2}{% \TransBlankPage{}% See translations file }% \end{center} }% \DeclareNewLayer[% Create new layer under some name foreground,% textarea,% contents=\blankpage,% ]{blankpage.fg} \DeclarePageStyleByLayers{blank}{blankpage.fg}% Make layer available as pagestyle \KOMAoptions{cleardoublepage=blank}% Use pagestyle %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Typesetting %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Using 'shortcuts' package option, do e.g. 'fast\-/paced' to get a breakable % 'fast-pace' word in print. % Otherwise, LaTeX does not hyphenate/linebreak words that already come with a hyphen, % since that could be ambiguous \RequirePackage[shortcuts]{extdash} \RequirePackage{microtype}% Advanced typesetting for kerning etc. % Dummy text in readable English (Other languages are also detected) % Provides a more realistic preview than Lorem Ipsum \RequirePackage{blindtext} \RequirePackage{pdflscape}% Pages in landscape format \RequirePackage{url}% Escaping special chars as URL %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Language Support %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{polyglossia}% Language rules. Replacement for babel in lualatex % Expand this properly; the version without \expandsafters does not work fully. % It works this way: % The first \expandafter is seen, so the following \setdefaultlanguage is not % expanded and skipped. % Next, the second \expandafter is looked at. It sees the token { next, saving it % for later. % \acp@language is then expanded fully, to the current language. % What is left is a properly working string, \setdefaultlanguage{} \expandafter\setdefaultlanguage\expandafter{\acp@language } % Whatever main language (setmainlanguage = setdefaultlanguage) was loaded, we want % the "other" one (since we expect only English and German) to be available as a % secondary language. This is very convenient if for example a thesis is in English, % but certain parts have to be in German, e.g. for legal reasons. A simple switch % \begin{german} ... \end{german} would then achieve that. \setotherlanguages{german,english} % Proper quotation support, mainly through \enquote \RequirePackage[ autostyle=true,% true always adapts quotes to current language ] {csquotes} % Add itshape to beginning (beg) of display quote environments: \renewcommand*{\mkbegdispquote}[2]{\itshape} \RequirePackage[inline]{enumitem}% Custom list environments \setlist{noitemsep}% No vertical spacing in lists \setlist[1]{labelindent=\parindent}% Indent lists by paragraph indent % Refer to unimath_symbols.pdf for source of \smblksquare etc.: % https://ctan.org/texarchive/macros/latex/contrib/unicode-math \setlist[itemize,1]{label=\smblksquare}% \setlist[enumerate]{font=\sffamily\bfseries} % For compact itemize lists within table cells: \newlist{tabitemize}{itemize}{1}% Second argument is max. depth \setlist[tabitemize]{% label=\smblksquare,% nosep,% nosep kills all vertical spacing align=parleft, leftmargin=*, % https://tex.stackexchange.com/a/443573/120853, % but before=\compress didn't work: after=\vspace{-\baselineskip}, before=\vspace{-0.75\baselineskip},% Hacky manual parameter } % For compact enumerations lists within table cells: \newlist{tabenum}{enumerate}{1}% Second argument is max. depth \setlist[tabenum]{ label={\arabic*.}, font=\sffamily\bfseries, leftmargin=*, nosep,% nosep kills all vertical spacing align=parleft, % https://tex.stackexchange.com/a/443573/120853, % but before=\compress didn't work: after=\vspace{-\baselineskip}, before=\vspace{-0.75\baselineskip},% Hacky manual parameter } % An enumerated description list: % https://tex.stackexchange.com/a/30035/120853 \newcounter{descriptcount} \newlist{enumdescript}{description}{2}% Derive from existing description env. \setlist[enumdescript, 1]{% Set first level action before={% \setcounter{descriptcount}{0}% % \renewcommand*\thedescriptcount{\alph{descriptcount}}% }, font={\bfseries\stepcounter{descriptcount}\thedescriptcount.~} } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Floats %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Does \centering automatically, provides side captions (fcapside) and much more. \RequirePackage{floatrow} \floatsetup{footposition=bottom}% For all floats \floatsetup[longtable]{LTcapwidth=table}% https://tex.stackexchange.com/a/345772/120853 \floatsetup[table]{% style=plaintop,% Always above, no matter where \caption is called footnoterule=none,% footskip=.35\skip\footins,% }% \floatsetup[figure]{% capbesideposition=right,% capbesidesep=quad,% }% \floatsetup[subfigure]{style=plain}% Plain style, so no rules %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Float Captions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{caption} % Will be printed between 'Figure/Table/... XYZ' and the caption text: \DeclareCaptionLabelSeparator{slash}{\ /\ }% `\ ' (backslash+space) is a short space \DeclareCaptionFont{ftfont}{% \scriptsize% \color{g3}% \hypersetup{hidelinks}% \sffamily\raggedleft% }% \captionsetup{% All captions format=plain,% textformat=period,% Always print period at end font=small,% All fonts labelfont={sf,bf},% labelsep=slash,% labelformat=simple,% Just Name/Number, no period or similar indention=1em,% }% \captionsetup[floatfoot]{% footfont=ftfont,% https://tex.stackexchange.com/q/9547/120853 }% \captionsetup[capbesidefigure]{ % When using sidecaptions, the linewidth can be rather small and awkward breaks and % many underfull hboxes occur. Therefore, raggedright. justification=raggedright, } \captionsetup[subfigure]{% labelformat=simple,% 'parens' uses parantheses, 'brace' just the right one labelsep=slash,% labelfont={sf,bf},% list=off,% list=off removes subfigures from LoF }% \captionsetup[subtable]{% labelformat=simple,% 'parens' uses parantheses, 'brace' just the right one labelsep=slash,% labelfont={sf,bf},% list=off,% list=off removes subfigures from LoF }% % Change counter from Arabic number to letter: \renewcommand*{\theContinuedFloat}{\alph{ContinuedFloat}} % Make this new length and indent, same length as regular caption indent: \newlength{\floatfootruleindent} \setlength{\floatfootruleindent}{\caption@indent}% Set the new length % A bit hacky; introduce a rule underneath caption if \floatfoot is called: \renewcommand*{\floatfootskip}{2pt\hspace{\floatfootruleindent}\hrulefill}% \RequirePackage{subcaption}% For subfloats %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Bibliography %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage[% Default back-end: biber % short style is 'alphabetic' (like [AB99]); % longer: 'authoryear' (like (Einstein, 1940)): style=authoryear, autocite=footnote,% Control what \autocite does % sortcites=true,% Apply what is specified in sorting= % Introduce back references in bibliography: % https://tex.stackexchange.com/a/211631/120853 % Do not use hyperref for this backref, url=false,% Still prints URL for @online, but nowhere else doi=false,% isbn=false,% ]{biblatex}% % The `\addbibresource` command moved to the root *.tex file to work for VSCode's % LaTeX Workshop extension. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Special Treatment for anything in \nocite{*} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Provides a category/sub-bibliography where all entries that occur in the bib- % file(s) but were not actually cited occur. Kind of like a "Further Reading". % New heading \defbibheading{notcited}{% \section*{% \TransFurtherReadingTitle{}% }% }% \defbibnote{further}{% \textit{\TransFurtherReadingText{}}% }% % https://tex.stackexchange.com/a/280545/120853 \DeclareBibliographyCategory{cited} \AtEveryCitekey{\addtocategory{cited}{\thefield{entrykey}}} % A header for when the bibliography is divided per-chapter: \defbibheading{subbibliography}{% \section*{% \Cref{refsegment:\therefsection\therefsegment}% }% }% % https://tex.stackexchange.com/a/477525/120853 \defbibenvironment{bibnonum}{ \list{% % }{% \setlength{\leftmargin}{\bibhang}% \setlength{\itemindent}{-\leftmargin}% \setlength{\itemsep}{\bibitemsep}% \setlength{\parsep}{\bibparsep} }% }% {\endlist}% {\item} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Arrays / Tables %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{tabu}% For longtabu in the glossary \RequirePackage{array} \newcolumntype{M}[1]{>{\centering\arraybackslash}m{#1}}% Vert.+Hor. centered cells % A command to have a cell with vertical text as a multirow: \newcommand*{\multirotatecell}[2]{% \multirow{#1}{*}{% \begin{tabular}{@{}c@{}}% \rotatebox[origin=c]{90}{#2}% \end{tabular}% }% }% \RequirePackage{tabularray}% Powerful, up and coming package \UseTblrLibrary{booktabs}% Get `\toprule` etc. for tabularrays \UseTblrLibrary{siunitx}% Get S column type \RequirePackage{multirow}% Cells spanning multiple rows (like multicolumn) \RequirePackage{booktabs}% Pretty tables; an absolute must % More vertical stretch for more relaxed visuals in all tables (global setting) \renewcommand*{\arraystretch}{1.3} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Other %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Replaces datetime; use regional date format from document language \RequirePackage[useregional]{datetime2} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Visuals, Graphics, Drawing etc %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{censor} \ifacp@censoring % censor package censors by default; do nothing if censoring requested % TeX doesn't have \ifnot or similar, see also % https://tex.stackexchange.com/q/386093/120853 \else % Turn off if document option given \StopCensoring \fi \RequirePackage{cancel}% Cancel out math in equations \RequirePackage{setspace}% Line spacing, used for title page % To achieve a reasonable 'text color', i.e. 'filled-ness' of the text, % adjust line spacing. % Recommendation for Palatino fonts (TeX Gyre Pagella is a Palatino clone) is a % factor of 1.05. % Discussion: https://tex.stackexchange.com/q/31064/120853 % For German, we might even want to go higher to allow space for the many capital % letters. % Also note that inline-math will look terrible at too low leading/linespread \linespread{1.05} \KOMAoption{singlespacing}{true}% Do not apply changed linespread to header/footer % Print a contour around letters, e.g. black text with a white border on some noisy % background, so that text remains legible. % NOT COMPATIBLE WITH XELATEX! Requires pdflatex or lualatex (our case) \RequirePackage[outline]{contour} \contourlength{0.12em} \newcommand*{\ctrw}[1]{% Black text, white contour \hypersetup{hidelinks}% Hide links, which might be colored \contour{white}{\textcolor{black}{#1}}% }% \newcommand*{\ctrb}[1]{% White text, black contour \hypersetup{hidelinks}% Hide links, which might be colored \contour{black}{\textcolor{white}{#1}}% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Graphics + Path %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{graphicx} % Set a global standard path, so don't specify ourselves each time; % only do bitmaps here, vectors are handled by the svg package and its path specs \graphicspath{{images/bitmaps/}} \RequirePackage{svg} % See also: % https://tex.stackexchange.com/a/158612/120853. % pdftexcmds package etc. no longer seems necessary. % svg package documentation states that it is a dependency, but done automatically. % https://tex.stackexchange.com/a/74693/120853 % Build failed on my system due to lack of the 'canberra' module, % see for a fix: https://askubuntu.com/a/872397/978477 % Running the document to generate the PDF and PDF_TEX file from the original SVG % will require SHELL ESCAPE (--shell-escape), aka elevation. % However, after the auxiliary images have been created, they only need to be input; % shell-escape will no longer be required. \svgpath{images/vectors/}% Analogous to \graphicspath{} \svgsetup{% inkscapepath=svgsubdir,% Put into subdirectory of where original SVG was found % In most cases, we include SVGs that contain no text, then add it in a % tikzpicture overlay. Therefore, don't generate *.pdf_tex file. % Toggle this back to true wherever needed, on a per-file basis inkscapelatex=false, } % When placing nodes over included SVGs using Tikz, % we require some help to debug the positions: \newcommand*{\debugtikzsvg}{% % This has to be evoked within a TikZ scope of: % `\begin{scope}[x={(image.south east)},y={(image.north west)}]` % The image we invoke the grid "on top of" needs to be labelled "image": \draw[help lines, xstep=0.02,ystep=0.02, opacity=0.5] (image.south west) grid (image.north east); \draw[gray, thick, xstep=0.1,ystep=0.1, opacity=0.8] (image.south west) grid (image.north east); % \foreach \posfraction in {% 0, 0.1, ...,1% }{% \foreach \startpoint/\endpoint/\nodeorientation in {% 2D-grid south west/south east/below,% north west/north east/above,% south east/north east/right,% south west/north west/left% }{ \node[\nodeorientation, opacity=0.5] at ($(image.\startpoint)!\posfraction!(image.\endpoint)$) {% \pgfmathparse{int(\posfraction*10)}% Round result \num{\pgfmathresult}% }; }% }% }% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Custom Symbols %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{scalerel}% Scale stuff relative to e.g. letters % Wrapper to include vectors icons by filename and scale them \newcommand*{\mtlbsmlkicon}[1]{% \scalerel*{% \includesvg{logos/matlab_simulink/#1}% }{% X% Scale first argument to height for capital X }% }% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Tikz + Plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{pgfplots}% Also loads Tikz % For advanced table calcs, e.g. 'y expr' to mathematically process input data: \RequirePackage{pgfplotstable} \RequirePackage[edges]{forest}% Comprehensive trees \RequirePackage{tikz-3dplot} % Only use libraries as needed to keep compilation times low \usetikzlibrary{% positioning,% Relative positioning etc. calc,% Calculate distances, coordinates etc. shapes, % For cross out backgrounds,% Draw on background layer fit,% Fit new node around existing coordinates decorations, arrows, arrows.spaced, intersections, trees, circuits.ee.IEC,% Electrical engineering circuits lib patterns, 3d, tikzmark,% Marks/coordinates at arbitrary positions }% \usepgfplotslibrary{% colorbrewer,% units,% dateplot, fillbetween, groupplots, }% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Colour Cycle for plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \pgfplotscreateplotcyclelist{mod RdYlBu3}{% Modify existing colorbrewer {rdylbu2}, {black!50}, {rdylbu5}% No comma or space here! }% \pgfplotscreateplotcyclelist{mod mark list}{% Modify predefined to start without mark every mark/.append style={solid,fill=\pgfplotsmarklistfill}\\ every mark/.append style={solid,fill=\pgfplotsmarklistfill},mark=*\\ every mark/.append style={solid,fill=\pgfplotsmarklistfill},mark=square*\\ every mark/.append style={solid,fill=\pgfplotsmarklistfill},mark=triangle*\\ every mark/.append style={solid},mark=star\\ every mark/.append style={solid,fill=\pgfplotsmarklistfill},mark=diamond*\\ every mark/.append style={solid,fill=\pgfplotsmarklistfill!40},mark=otimes*\\ every mark/.append style={solid},mark=|\\ every mark/.append style={solid,fill=\pgfplotsmarklistfill},mark=pentagon*\\ }% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Global plot settings %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \pgfplotstableset{col sep=comma}% If ALL files/tables are comma-separated \pgfplotsset{% % Version this document was originally created with; % see also https://tex.stackexchange.com/a/81912/120853 % Important for reproducibility compat=1.16, % In case nodes reach out of plot area, dont clip them off. % See: https://tex.stackexchange.com/a/127904/120853 and % https://tex.stackexchange.com/a/311194/120853 clip mode=individual, label style={font=\small},% https://tex.stackexchange.com/a/300673/120853 tick label style={% font=\small,% /pgf/number format/1000 sep={\,}% Small space instead of comma }, cycle multi list={% mod mark list\nextlist% Just in case; likely never reached linestyles*\nextlist % Iterate through last one first; if at end, % start anew using next in parent (linestyles *): mod RdYlBu3% },% colormap/viridis,% For 3D/surf plots legend style={% at={(0.5,1.05)},% Center hor. (0.5), slightly out of drawing(>1 vert.) anchor=south,% legend columns=-1,% -1 means only rows, as many columns as required font=\footnotesize,% draw=none,% Do not draw box fill=none,% No white fill. Important for gray backgrounds },% % These comment lines (visual separation) are super important. % Empty lines will throw errors here! unit code/.code 2 args={\unit{#1#2}},% Use siunitx for units library unit markings={slash space},% The proper way... apparently? % % Fix micro unit display, see https://tex.stackexchange.com/a/224574/120853: x SI prefix/micro/.style={/pgfplots/axis base prefix={axis x base 6 prefix \micro}}, y SI prefix/micro/.style={/pgfplots/axis base prefix={axis y base 6 prefix \micro}}, z SI prefix/micro/.style={/pgfplots/axis base prefix={axis z base 6 prefix \micro}}, % % Plot styles: regularplot/.style={% A broadly usable, regular plot ultra thick, axis line style=thick, ymajorgrids=true, xmajorgrids=true, grid style=dashed, axis lines=left, % scale only axis,% If off, labels are taken into account for size calculations ytick align=outside,% Puts ticks outside the plot itself xtick align=outside,% % Won't work if enlarge limits are invoked before 'axis lines left': enlargelimits=0.05, },% plainplot/.style={% % A clean, simple plot when numerical values and labels don't matter regularplot, xmajorgrids=false, ymajorgrids=false, ticks=none,% No ticks with numbers }, tuftelike/.style={% https://tex.stackexchange.com/a/155210/120853 axis line shift=10pt,% Also shifts label automatically try min ticks=3,% https://tex.stackexchange.com/a/95753/120853 max space between ticks=50,% High number so ticks are far apart axis lines=left, ultra thick, axis line style = {semithick, -},% '-' suppresses arrow tick style = {semithick, black},% ytick align=inside,% Puts ticks inside the plot itself xtick align=inside,% xtick={% % Always set min, max and middle ticks; % if more desired, use 'extra x ticks={}' \pgfkeysvalueof{/pgfplots/xmin}, \pgfkeysvalueof{/pgfplots/xmax}, (\pgfkeysvalueof{/pgfplots/xmax}+\pgfkeysvalueof{/pgfplots/xmin})/2 }, ytick={% Same as x \pgfkeysvalueof{/pgfplots/ymin}, \pgfkeysvalueof{/pgfplots/ymax}, (\pgfkeysvalueof{/pgfplots/ymax}+\pgfkeysvalueof{/pgfplots/ymin})/2 }, clip = false,% https://tex.stackexchange.com/a/311194/120853 },% % Unfortunately, decorations lib is relatively verbose: arrowplot/.style={ decoration={ markings, mark=at position 0.25 with {\arrow{#1}}, mark=at position 0.5 with {\arrow{#1}}, mark=at position 0.75 with {\arrow{#1}}, }, postaction=decorate, }, % log x ticks with fixed point/.style={% % Logarithmic plot, but with linear labels instead of scientific notation % (10^2 becomes 100 etc.) % https://tex.stackexchange.com/a/139084/120853 xticklabel={ \pgfkeys{/pgf/fpu=true} \pgfmathparse{exp(\tick)}% \pgfmathprintnumber[fixed relative, precision=3]{\pgfmathresult} \pgfkeys{/pgf/fpu=false} } }, % log y ticks with fixed point/.style={ yticklabel={ \pgfkeys{/pgf/fpu=true} \pgfmathparse{exp(\tick)}% \pgfmathprintnumber[fixed relative, precision=3]{\pgfmathresult} \pgfkeys{/pgf/fpu=false} } } } % Required in \tikset body for node placing at x style. % Requires intersection lib % https://tex.stackexchange.com/a/93968/120853 \def\parsenode[#1]#2\pgf@nil{% \tikzset{label node/.style={#1}} \def\nodetext{#2} } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Various thermodynamic/mechanical/technical shapes, usable in regular TikZ graphics. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \tikzset{ >=stealth',% Global arrow style % % Flow chart styles startstop/.style={% rectangle, rounded corners, minimum width=40mm, minimum height=1cm, text centered, draw=black, fill=red!30, }, io/.style={% ellipse, minimum width=35mm, minimum height=10mm, text width=35mm, text centered, inner xsep=-1ex, draw=black, fill=blue!30, }, process/.style={% rectangle, minimum width=40mm, minimum height=1cm, text centered, text width=40mm, draw=black, fill=orange!30, }, decision/.style={% signal, signal to=east and west, minimum width=40mm, minimum height=1cm, text width=40mm, text centered, inner xsep=-1ex, draw=black, fill=green!30, }, arrow/.style={% thick, ->, >=stealth, }, % symmetrycross/.style={% % Style for a center-cross to mark symmetry in technical drawings. % Styles have one argument per default. Use it for size, % but also provide a default draw, cross out,% From shapes library thin, dashdotted, rotate=45, minimum size=#1,% This is an argument }, symmetrycross/.default={2em}, pipecrosssection/.style={ circle, minimum size=#1, draw=black!90!red, ultra thick,% Simulate thick pipe around it fill=MediumFluid }, pipecrosssection/.default={0.5em}, arrowlabel/.style={ % Style for labels along arrows pos=#1, text=black,% Overwrite in case encapsulating draw command is white etc. draw=none,% Do not draw border fill=white, inner sep=1.5pt, rounded corners, }, arrowlabel/.default={0.5}, % Default for position: middle wall/.style={ % For all walls, e.g. in crosssections of pipes, ... draw, thick, fill=#1, line join=round, rounded corners=0.5, }, wall/.default={g5}, fluid/.style={ % For all fluids fill=#1, }, fluid/.default={MediumFluid}, flowarrow/.style 2 args={% A style for squiggly arrows, for flows: ->, line join=round, thick, dashed, decorate, decoration={ snake, % alternatives: snake, zigzag segment length=#1, amplitude=#2, % Stop with decoration at start and end by the given length and just draw % a line: pre=lineto, post=lineto, pre length=1em, post length=1em }, }, annotationarrow/.style={% % A style intended to point a line with a thick black dot at its end onto % elements to give further explanations. % Since we shorten the line START, any line using this style should originate % from the place where the shortening is supposed to take place. % Further explanation here: % https://tex.stackexchange.com/a/115268/120853 % Simply call -* (or any other similar command) after annoationarrow if the % direction should be inverted. *-, shorten <=-(1.8pt + 1.4\pgflinewidth),% }, flowarrow/.default={3em}{2em},% {}{} origindot/.style={ % A simple small dot for coordinate starts/origins circle, fill=#1, inner sep=0pt, minimum width=0.4em }, origindot/.default={black}, add node at x/.style 2 args={% https://tex.stackexchange.com/a/93968/120853 % Add node on a plot by just specifying its x-position. % The corresponding y/value is computed automatically! name path global=plot line, /pgfplots/execute at end plot visualization/.append={ \begingroup \@ifnextchar[{\parsenode}{\parsenode[]}#2\pgf@nil \path [name path global=position line #1-1] ({axis cs:#1,0}|-{rel axis cs:0,0}) -- ({axis cs:#1,0}|-{rel axis cs:0,1}); \path [xshift=1pt, name path global=position line #1-2] ({axis cs:#1,0}|-{rel axis cs:0,0}) -- ({axis cs:#1,0}|-{rel axis cs:0,1}); \path [ name intersections={ of={plot line and position line #1-1}, name=left intersection }, name intersections={ of={plot line and position line #1-2}, name=right intersection }, label node/.append style={pos=1} ] (left intersection-1) -- (right intersection-1) node [label node]{\nodetext}; \endgroup } }, shorten <>/.style={% Allow shortening of both ends simultaneously shorten >=#1, shorten <=#1, }, circlednum/.style={% Used for a custom circled number command shape=circle, draw, inner sep=2pt, fill=white }%, % A reusable little 'pic' for a common radiator. % Further down, we also declare a 'shape' for a radiator. A 'shape' is a node shape with anchors etc. and intended to be used to connect nodes together, like in a circuit diagram. % A 'pic' is really just a reusable picture that can be put anywhere, but it (by the package author) not intended to be connected etc. % This pic is prettier than the shape below. The pic should be used for large radiator images where more detail is desired. radiator/.pic={ \tikzset{% every path/.style={ draw, thick, line join=round, line cap=round,% End of lines fill=g5, pic actions,% Whatever is used in \pic[], e.g. dashed, is propagated to this drawing }, } % Base measurements. Default unit is centimeter \pgfmathsetmacro{\radiatorheight}{2} \pgfmathsetmacro{\radiatorwidth}{3} \pgfmathsetmacro{\radiatordepth}{0.5} % Right surface: \begin{scope}[canvas is yz plane at x=\radiatorwidth] \draw[fill=g4] (0,0) rectangle (\radiatorheight,\radiatordepth); % Fake the thermostat a bit: \draw[fill=g3] (0.8*\radiatorheight,0.5*\radiatordepth) circle (0.2*\radiatordepth); % Generate some coordinates in analogy to regular tikz naming convetions: \foreach \yfrac/\zfrac/\coordname in {% 0.5/0.5/center,% 0/0.5/south,% 1/0.5/north,% 0.5/0/east, 0.5/1/west, 0/0/south east,% 0/1/south west,% 1/1/north east,% 1/0/north west,% 0.8/0.5/thermostat% }{ \coordinate (-right \coordname) at (\yfrac*\radiatorheight,\zfrac*\radiatordepth); } \end{scope} % Top surface: \begin{scope}[canvas is xz plane at y=\radiatorheight] \draw (0,0) rectangle (\radiatorwidth,\radiatordepth); % "Hollow space" inside the radiator: \draw[fill=g2, rounded corners=0.75] (0.05*\radiatorwidth,0.3*\radiatordepth) rectangle (0.95*\radiatorwidth,0.7*\radiatordepth); % Generate some coordinates in analogy to regular tikz naming convetions: \foreach \xfrac/\zfrac/\coordname in {% 0.5/0.5/center,% 0.5/1/south,% 0.5/0/north,% 1/0.5/east, 0/0.5/west, 1/1/south east,% 0/1/south west,% 1/0/north east,% 0/0/north west% }{ \coordinate (-top \coordname) at (\xfrac*\radiatorwidth,\zfrac*\radiatordepth); } \end{scope} % Front surface: \begin{scope}[canvas is xy plane at z=\radiatordepth] \draw (0,0) rectangle (\radiatorwidth,\radiatorheight); \foreach \posfraction in {0.1, 0.2, ..., 0.9} {% \draw[ thick, preaction={draw, ultra thick, g3}, ] (\posfraction*\radiatorwidth, 0.1*\radiatorheight) -- (\posfraction*\radiatorwidth, 0.9*\radiatorheight); } % Generate some coordinates in analogy to regular tikz naming convetions: \foreach \xfrac/\yfrac/\coordname in {% 0.5/0.5/center,% 0.5/0/south,% 0.5/1/north,% 1/0.5/east, 0/0.5/west, 1/0/south east,% 0/0/south west,% 1/1/north east,% 0/1/north west% }{ \coordinate (-front \coordname) at (\xfrac*\radiatorwidth,\yfrac*\radiatorheight); } \node at (-front center) {\ctrw{\tikzpictext}};% value of "pic text" key is stored in \tikzpictext macro \end{scope} % Coordinates for convenience: \coordinate (-thermostat) at (-right thermostat); \coordinate (-entry) at ($(-front north west)!0.2!(-front south west)$); \coordinate (-exit) at ($(-right south)!0.2!(-right north)$); \coordinate (-left center) at (-front west|--right center);% To have an exact opposite of the visible 'center right' position % Debugging coordinate system: % \draw[->] (0,0,0) -- (1,0,0) node[right] {\(x\)}; % \draw[->] (0,0,0) -- (0,1,0) node[left] {\(y\)}; % \draw[->] (0,0,0) -- (0,0,1) node[above] {\(z\)}; }, TUHHuman/.pic={% A human member of TUHH. Hilarious...... \pgfmathsetmacro{\roundingradius}{0.4} \filldraw[pic actions] (0,0) circle (1);% Head % % Use arc over just specifying 'rounded corners', because rounded corners are absolute and aren't affected by 'scale' \filldraw[pic actions] (0,-1.2)% Below head -- ++ (2.5-\roundingradius,0) arc (90:0:\roundingradius)% Right shoulder -- ++ (0,{-(5 - 2*\roundingradius)}) arc (0:-90:\roundingradius) -- ++ ({-(0.8 - 2*\roundingradius)},0) arc (270:180:\roundingradius) -- ++ (0,{4 - \roundingradius})% Right arm -- ++ (-0.25,0)% Right arm pit -- ++ (0,{-(8 - \roundingradius)}) arc (0:-90:\roundingradius) -- ++ ({-(1 - 2*\roundingradius)},0) arc (270:180:\roundingradius) -- ++ (0,{4 - 2*\roundingradius}) arc (0:90:\roundingradius)% Right leg -- ++ ({-(1 - 2*\roundingradius)},0)% Gap between legs arc (90:180:\roundingradius) -- ++ (0,{-(4 - 2*\roundingradius)}) arc (0:-90:\roundingradius) -- ++ ({-(1 - 2*\roundingradius)},0) arc (270:180:\roundingradius) -- ++ (0,{8 - \roundingradius})% Left leg -- ++ (-0.25,0)% Left arm pit -- ++ (0,{-(4 - \roundingradius)}) arc (0:-90:\roundingradius) -- ++ ({-(0.8 - 2*\roundingradius},0) arc (270:180:\roundingradius) -- ++ (0,{5 - 2*\roundingradius})% Left arm arc (180:90:\roundingradius)-- cycle;% Left shoulder; cycle back to below head \node[right, transform shape] at (-1.25,-2.5) {\ctrw{\textcolor[RGB]{45,198,214}{\textbf{\textsf{TUHH}}}}};% Chest emblem; transform shape allows node to be affected by 'scale' option % % \draw[help lines] (-3,-11) grid (3,1);% Debugging grid }, boilercylinder/.style={ cylinder,% Shapes lib draw, thick, shape border rotate=90, aspect=0.3,% Flatten cylinder uses custom fill, % cylinder body fill=g5,% For regular filling, use these and comment out the colors at the bottom here % cylinder end fill=g4,% left color=HotFluid!70, middle color=orange!20, right color=g4, shading angle=180, }, % Still use a pic so we can flexible add stuff to all boilers later one, like a burner on the bottom left side: boiler/.pic={ \node[ boilercylinder, minimum width=4em, minimum height=6em, pic actions,% Whatever is used in \pic[], e.g. dashed, is propagated to this drawing ] () {\ctrw{\tikzpictext}};% Empty coordinate is important for namespace stuff }, equalizing tank/.style={ circle split, draw, solid,% In case surrounding context is dashed etc. -,% As opposed to arrows etc. fill=white, double, minimum width=#1, }, equalizing tank/.default={1.5em}, pipe/.style={% (Water) pipes between devices. For a pipe without arrow line end, call it as e.g. \draw[pipe, -] line width=#1, double=MediumFluid, double distance={1*#1}, -{Triangle Cap []. Fast Triangle[] Fast Triangle[] Fast Triangle[]},% dot represents line end line join=round, }, pipe/.default={1.5pt}, valve/.style={ shape=valve, draw, solid,% In case surrounding context is dashed etc. -,% As opposed to arrows etc. fill=white, rounded corners=0.5, rotate=90,% We probably need the horizontal version more often. Also, this way, \draw ... node[midway, valve, sloped] {}; works out of the box minimum width=0.6*#1,% Fixed aspect ratio minimum height=#1, }, valve/.default={1em}, control valve/.style={% Same node style but different shape valve, % blue!10, shape=controlvalve, }, threeway valve/.style={ valve, shape=threeway valve, minimum width=0.85*#1,% Scale it a bit... minimum height=#1, }, threeway valve/.default={1em}, fourway valve/.style={ valve, rotate=-90,% It's symmetrical, no need to rotate; undo inherited rotation shape=fourway valve, minimum width=#1,% Fixed aspect ratio, square minimum height=#1, }, fourway valve/.default={1em}, threeway control valve/.style={ threeway valve, shape=threewaycontrolvalve, }, radiator/.style={ shape=radiator, draw, fill=g6, line join=round, minimum width=#1, minimum height=(2/3)*#1,% Fixed aspect ratio }, radiator/.default={3em}, vented radiator/.style={ radiator,% Inherit from style shape=vented radiator,% Different shape }, pump/.style={ shape=pump, draw, solid,% In case surrounding context is dashed etc. -,% As opposed to arrows etc. fill=white, line join=round, minimum width=#1, rounded corners=0.5,% Alter rounded corners in case surrounding style has them }, pump/.default={1.5em}, compressor/.style={ shape=compressor, draw, solid, -, fill=white, line join=round, minimum size=#1, sloped,% Because why not }, compressor/.default={1.5em}, heat exchanger/.style={ shape=heat exchanger, draw, solid, -, fill=white, line join=round, rounded corners=0.5, minimum width=#1, minimum height=0.5*#1,% Fixed aspect ratio sloped,% Because why not }, heat exchanger/.default={1.5em}, simple heat exchanger/.style={ shape=simple heat exchanger, draw, solid, -, fill=white, line join=round, minimum width=#1, minimum height=2/3*#1,% Fixed aspect ratio sloped,% Because why not }, simple heat exchanger/.default={1.5em}, sensor/.style={% A vertical stroke with with three horizontal lines of decreasing width underneath shape=sensor, draw, solid, -, line join=round, line cap=round, minimum width=#1, minimum height=2*#1 }, sensor/.default={0.5em}, level indicator/.style={% An upside-down triangle with three horizontal lines of decreasing width underneath shape=levelindicator, draw, fill=white, solid, -, line join=round, line cap=round, minimum width=#1, minimum height=2*#1, inner sep=1.5pt, }, level indicator/.default={0.25em} } \pgfdeclareshape{valve}{% \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough \inheritanchorborder[from=rectangle] \inheritanchor[from=rectangle]{north} \inheritanchor[from=rectangle]{north west} \inheritanchor[from=rectangle]{north east} \inheritanchor[from=rectangle]{center} \inheritanchor[from=rectangle]{west} \inheritanchor[from=rectangle]{east} \inheritanchor[from=rectangle]{mid} \inheritanchor[from=rectangle]{mid west} \inheritanchor[from=rectangle]{mid east} \inheritanchor[from=rectangle]{base} \inheritanchor[from=rectangle]{base west} \inheritanchor[from=rectangle]{base east} \inheritanchor[from=rectangle]{south} \inheritanchor[from=rectangle]{south west} \inheritanchor[from=rectangle]{south east} \backgroundpath{% % Store lower left in xa/ya and upper right in xb/yb \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y % Construct main path, basically 'two triangles touching' \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}} \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}} \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}} \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}} \pgfpathclose } } \pgfdeclareshape{threeway valve}{ % This is asymetrical and stuff, so inheriting from the base valve is a bit hopeless, I don't know how to do it properly \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough \inheritanchorborder[from=rectangle] \inheritanchor[from=rectangle]{north west} \inheritanchor[from=rectangle]{north east} \inheritanchor[from=rectangle]{center} \inheritanchor[from=rectangle]{west} \inheritanchor[from=rectangle]{east} \inheritanchor[from=rectangle]{mid} \inheritanchor[from=rectangle]{mid west} \inheritanchor[from=rectangle]{mid east} \inheritanchor[from=rectangle]{base} \inheritanchor[from=rectangle]{base west} \inheritanchor[from=rectangle]{base east} \inheritanchor[from=rectangle]{south west} \inheritanchor[from=rectangle]{south east} % These have shifted now, since the three-point valve middle is not the node center anymore: \anchor{center}{ \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y \pgfmathsetlength\pgf@x{\pgf@xa + 0.5*0.75*(\pgf@xb - \pgf@xa)} \pgfmathsetlength\pgf@y{\pgf@ya + 0.5*(\pgf@yb - \pgf@ya)} } \anchor{north}{ \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y \southwest \pgf@xa=\pgf@x \pgfmathsetlength\pgf@x{\pgf@xa + 0.5*0.75*(\pgf@xb - \pgf@xa)} \pgfmathsetlength\pgf@y{\pgf@yb} } \anchor{south}{ \northeast \pgf@xb=\pgf@x \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y \pgfmathsetlength\pgf@x{\pgf@xa + 0.5*0.75*(\pgf@xb - \pgf@xa)} \pgfmathsetlength\pgf@y{\pgf@ya} } % The triangles meeting at their middle, each with an aspect ratio of 0.75 (base) to 0.5 (height) \backgroundpath{ \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y \pgfpathmoveto{\southwest} \pgfpathlineto{\pgfpoint{\pgf@xa + 0.75*(\pgf@xb - \pgf@xa)}{\pgf@yb}} \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}} \pgfpathlineto{\pgfpoint{\pgf@xa + 0.75*0.5*(\pgf@xb - \pgf@xa)}{\pgf@ya + 0.5*(\pgf@yb - \pgf@ya)}}% Valve centerpoint \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya + 0.8*(\pgf@yb - \pgf@ya)}} \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya + 0.2*(\pgf@yb - \pgf@ya)}} \pgfpathlineto{\pgfpoint{\pgf@xa + 0.75*0.5*(\pgf@xb - \pgf@xa)}{\pgf@ya + 0.5*(\pgf@yb - \pgf@ya)}}% Valve centerpoint \pgfpathlineto{\pgfpoint{\pgf@xa + 0.75*(\pgf@xb - \pgf@xa)}{\pgf@ya}} \pgfpathclose } } \pgfdeclareshape{fourway valve}{% \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough \inheritanchorborder[from=rectangle] \inheritanchor[from=rectangle]{north} \inheritanchor[from=rectangle]{north west} \inheritanchor[from=rectangle]{north east} \inheritanchor[from=rectangle]{center} \inheritanchor[from=rectangle]{west} \inheritanchor[from=rectangle]{east} \inheritanchor[from=rectangle]{mid} \inheritanchor[from=rectangle]{mid west} \inheritanchor[from=rectangle]{mid east} \inheritanchor[from=rectangle]{base} \inheritanchor[from=rectangle]{base west} \inheritanchor[from=rectangle]{base east} \inheritanchor[from=rectangle]{south} \inheritanchor[from=rectangle]{south west} \inheritanchor[from=rectangle]{south east} \backgroundpath{% % Store lower left in xa/ya and upper right in xb/yb \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y % This yields four triangles meeting in the middle, each with an aspect ratio of 0.6/1. % Construct main path, basically 'two triangles touching' \pgfpathmoveto{\pgfpoint{\pgf@xa + 0.2*(\pgf@xb - \pgf@xa)}{\pgf@ya}} \pgfpathlineto{\pgfpoint{\pgf@xa + 0.8*(\pgf@xb - \pgf@xa)}{\pgf@yb}} \pgfpathlineto{\pgfpoint{\pgf@xa + 0.2*(\pgf@xb - \pgf@xa)}{\pgf@yb}} \pgfpathlineto{\pgfpoint{\pgf@xa + 0.8*(\pgf@xb - \pgf@xa)}{\pgf@ya}} \pgfpathclose % Do the same again in the horizontal direction: \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya + 0.2*(\pgf@yb - \pgf@ya)}} \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@ya + 0.8*(\pgf@yb - \pgf@ya)}} \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya + 0.2*(\pgf@yb - \pgf@ya)}} \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya + 0.8*(\pgf@yb - \pgf@ya)}} \pgfpathclose } } \pgfdeclareshape{controlvalve}{ \inheritsavedanchors[from=valve] \inheritanchorborder[from=valve] \inheritanchor[from=valve]{north} \inheritanchor[from=valve]{north west} \inheritanchor[from=valve]{north east} \inheritanchor[from=valve]{center} \inheritanchor[from=valve]{west} \inheritanchor[from=valve]{east} \inheritanchor[from=valve]{mid} \inheritanchor[from=valve]{mid west} \inheritanchor[from=valve]{mid east} \inheritanchor[from=valve]{base} \inheritanchor[from=valve]{base west} \inheritanchor[from=valve]{base east} \inheritanchor[from=valve]{south} \inheritanchor[from=valve]{south west} \inheritanchor[from=valve]{south east} \inheritbackgroundpath[from={valve}] \beforebackgroundpath{% % Store lower left in xa/ya and upper right in xb/yb \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y % Extension line to control wheel: \pgfpathmoveto{\pgfpoint{(\pgf@xa + \pgf@xb)/2}{(\pgf@ya + \pgf@yb)/2}} \pgfpathlineto{\pgfpoint{\pgf@xb}{(\pgf@ya + \pgf@yb)/2}} % The factors 0.3, 0.4 and 0.3 need to add up to 1 to give a symmetrical, nice semicircle. % Factor 0.4 is divided by 2 to give the radius \pgfpathmoveto{\pgfpoint{\pgf@xb}{\pgf@ya + 0.3*(\pgf@yb - \pgf@ya)}} \pgfpatharc{-90}{90}{0.4/2*(\pgf@yb - \pgf@ya)} \pgfpathclose \pgfsetfillcolor{black} \pgfusepath{fill, stroke} } } \pgfdeclareshape{pump}{% \inheritsavedanchors[from=circle]% \inheritanchorborder[from=circle] \inheritbackgroundpath[from={circle}] \inheritanchor[from=circle]{center} \inheritanchor[from=circle]{north} \inheritanchor[from=circle]{south} \inheritanchor[from=circle]{west} \inheritanchor[from=circle]{east} \beforebackgroundpath{ % The simple-most approach: \pgfpathmoveto{\pgf@anchor@pump@west} \pgfpathlineto{\pgf@anchor@pump@north} \pgfpathlineto{\pgf@anchor@pump@east} \pgfusepath{stroke} } } \pgfdeclareshape{compressor}{% \inheritsavedanchors[from=circle]% \inheritanchorborder[from=circle]% \inheritbackgroundpath[from={circle}]% \inheritanchor[from=circle]{center}% \inheritanchor[from=circle]{north}% \inheritanchor[from=circle]{south}% \inheritanchor[from=circle]{west}% \inheritanchor[from=circle]{east}% % Circle has savedanchor of 'centerpoint' and saveddim of 'radius', that's it \beforebackgroundpath{ \centerpoint \pgf@yc=\pgf@y % Pythagorean theorem is enough here. % Assumption is that default compressor shape 'points to the right'. % This is important to get coorect behaviour out of the 'sloped' node option! % Idea (Example for top right point): % 1. Go to center point. % 2. On y-axis, move a fraction of the radius up. This is the y-portion of our top-right coordinate point. % 3. On x-axis, move as far right as Pythagorean theorem dictates (hypotenuse is the radius vector, other known length is the y-length we just specified) % 4. Repeat process to draw and move accordingly; don't forget squares and sqrt() in correct places. \pgfmathsetmacro{\upperyfraction}{0.3}% y-coordinate of the upper points is \upperyfraction*\radius to the sides of the centerpoint \pgfmathsetmacro{\loweryfraction}{0.7}% y-coordinate of the lower points is \loweryfraction*\radius to the sides of the centerpoint \foreach \signdirection in {1, -1}{% For left and right side % Upper (always same x-dimension, only y switches sign): \pgfpathmoveto{\pgfpoint{sqrt(\radius^2 - (\pgf@yc + \upperyfraction*\radius)^2)}{\pgf@yc + \signdirection*\upperyfraction*\radius}} % Bottom (always same x-dimension, only y switches sign): \pgfpathlineto{\pgfpoint{-1*sqrt(\radius^2 - (\pgf@yc - \loweryfraction*\radius)^2)}{\pgf@yc + \signdirection*\loweryfraction*\radius}} } \pgfusepath{stroke} } } \pgfdeclareshape{heat exchanger}{ \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough. Rectangle has to 'saved anchors': southwest and northeast \inheritanchorborder[from=rectangle] % Doesn't hurt to also inherit specific anchors: \inheritanchor[from=rectangle]{north} \inheritanchor[from=rectangle]{north west} \inheritanchor[from=rectangle]{north east} \inheritanchor[from=rectangle]{center} \inheritanchor[from=rectangle]{west} \inheritanchor[from=rectangle]{east} \inheritanchor[from=rectangle]{mid} \inheritanchor[from=rectangle]{mid west} \inheritanchor[from=rectangle]{mid east} \inheritanchor[from=rectangle]{base} \inheritanchor[from=rectangle]{base west} \inheritanchor[from=rectangle]{base east} \inheritanchor[from=rectangle]{south} \inheritanchor[from=rectangle]{south west} \inheritanchor[from=rectangle]{south east} \inheritbackgroundpath[from={rectangle}] % Anchor to 'in' port of heat exchanger. % This code does not get executed necessarily; we cannot use the \pgfsetmacros from below. % A solution is probably \pgfkeys, but this will do for now. % IT NEEDS MANUAL ADJUSTING IF THE SHAPE IS CHANGED. \anchor{in}{% \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y \pgfmathsetlength\pgf@x{\pgf@xa + (1 - 0.7)/2*(\pgf@xb - \pgf@xa)} \pgfmathsetlength\pgf@y{\pgf@ya - 0.3*(\pgf@yb - \pgf@ya)} } \anchor{out}{% \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y \pgfmathsetlength\pgf@x{\pgf@xb - (1 - 0.7)/2*(\pgf@xb - \pgf@xa)} \pgfmathsetlength\pgf@y{\pgf@ya - 0.3*(\pgf@yb - \pgf@ya)} } \beforebackgroundpath{ \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y \pgfmathsetmacro{\heatsymbolextension}{0.3}% How far out the 'legs' extend out of the rectangle as a fraction of the overall node's height \pgfmathsetmacro{\heatsymbolwidth}{0.7}% The inner drawing's width as a fraction of the node's overall width \pgfmathsetmacro{\heatsymbolheight}{0.8}% How high the inner drawing reaches as a fraction of the node's overall height (at 1, it touches the upper rectangle border) \pgfmathsetmacro{\heatsymbolindentation}{0.3}% How 'indented' the triangle is, i.e. the vertical distance between the inner drawings highest point and the triangle's down-pointing 'tip' \pgfpathmoveto{\pgfpoint{\pgf@xa + (1 - \heatsymbolwidth)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya - \heatsymbolextension*(\pgf@yb - \pgf@ya)}}% Bottom left corner \pgfpathlineto{\pgfpoint{\pgf@xa + (1 - \heatsymbolwidth)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya + \heatsymbolheight*(\pgf@yb - \pgf@ya)}}% Straight line up \pgfpathlineto{\pgfpoint{\pgf@xa + 0.5*(\pgf@xb - \pgf@xa)}{\pgf@ya + (\heatsymbolheight - \heatsymbolindentation)*(\pgf@yb - \pgf@ya)}}% Line down, to the right; x-coordinate is the middle of the node \pgfpathlineto{\pgfpoint{\pgf@xb - (1 - \heatsymbolwidth)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya + \heatsymbolheight*(\pgf@yb - \pgf@ya)}}% Line up, to the right \pgfpathlineto{\pgfpoint{\pgf@xb - (1 - \heatsymbolwidth)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya - \heatsymbolextension*(\pgf@yb - \pgf@ya)}}% Line straight down \pgfusepath{stroke} } } \pgfdeclareshape{simple heat exchanger}{% Just a cross-out rectangle \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough. Rectangle has to 'saved anchors': southwest and northeast \inheritanchorborder[from=rectangle] % Doesn't hurt to also inherit specific anchors: \inheritanchor[from=rectangle]{north} \inheritanchor[from=rectangle]{north west} \inheritanchor[from=rectangle]{north east} \inheritanchor[from=rectangle]{center} \inheritanchor[from=rectangle]{west} \inheritanchor[from=rectangle]{east} \inheritanchor[from=rectangle]{mid} \inheritanchor[from=rectangle]{mid west} \inheritanchor[from=rectangle]{mid east} \inheritanchor[from=rectangle]{base} \inheritanchor[from=rectangle]{base west} \inheritanchor[from=rectangle]{base east} \inheritanchor[from=rectangle]{south} \inheritanchor[from=rectangle]{south west} \inheritanchor[from=rectangle]{south east} \inheritbackgroundpath[from={rectangle}] \beforebackgroundpath{ \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@yb}}% Top left corner \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}% Bottom right corner \pgfusepath{stroke} } } \pgfkeys{/pgf/.cd, radiator offset x/.initial=0.3em, radiator offset y/.initial=0.3em } \pgfdeclareshape{radiator}{% \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough. Rectangle has to 'saved anchors': southwest and northeast \inheritanchorborder[from=rectangle] % Doesn't hurt to also inherit specific anchors: \inheritanchor[from=rectangle]{north} \inheritanchor[from=rectangle]{north west} \inheritanchor[from=rectangle]{north east} \inheritanchor[from=rectangle]{center} \inheritanchor[from=rectangle]{west} \inheritanchor[from=rectangle]{east} \inheritanchor[from=rectangle]{mid} \inheritanchor[from=rectangle]{mid west} \inheritanchor[from=rectangle]{mid east} \inheritanchor[from=rectangle]{base} \inheritanchor[from=rectangle]{base west} \inheritanchor[from=rectangle]{base east} \inheritanchor[from=rectangle]{south} \inheritanchor[from=rectangle]{south west} \inheritanchor[from=rectangle]{south east} \saveddimen{\xoffset}{% https://tex.stackexchange.com/a/181283/120853 \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/radiator offset x}} } \saveddimen{\yoffset}{ \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/radiator offset y}} } % In the middle of the right surface: \anchor{right}{% \southwest \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y \pgfmathsetlength\pgf@x{\pgf@xb + \xoffset/2} \pgfmathsetlength\pgf@y{(\pgf@ya + \pgf@yb)/2 + \yoffset/2} } % In the middle of the top surface: \anchor{top}{% \southwest \pgf@xa=\pgf@x \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y \pgfmathsetlength\pgf@x{(\pgf@xa + \pgf@xb)/2 + \xoffset/2} \pgfmathsetlength\pgf@y{\pgf@yb + \yoffset/2} } % Exit at the thermostat: \anchor{exit}{% \southwest \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y \pgfmathsetlength\pgf@x{\pgf@xb + \xoffset/2} \pgfmathsetlength\pgf@y{\pgf@ya + 0.8*(\pgf@yb - \pgf@ya) + \yoffset/2} } % Lower exit on the right side, below the thermostat: \anchor{lower exit}{% \southwest \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y \pgfmathsetlength\pgf@x{\pgf@xb + \xoffset/2} \pgfmathsetlength\pgf@y{\pgf@ya + 0.2*(\pgf@yb - \pgf@ya) + \yoffset/2} } % Entry in the bottom left somewhere: \anchor{lower entry}{% \northeast \pgf@yb=\pgf@y \southwest \pgf@ya=\pgf@y% x is now given implicitly \pgfmathsetlength\pgf@y{\pgf@ya + 0.2*(\pgf@yb - \pgf@ya)} } % Alternative entry in the top left somewhere: \anchor{upper entry}{% \northeast \pgf@yb=\pgf@y \southwest \pgf@ya=\pgf@y% x is now given implicitly \pgfmathsetlength\pgf@y{\pgf@ya + 0.8*(\pgf@yb - \pgf@ya)} } % Front surface is inherited from rectangle: \inheritbackgroundpath[from={rectangle}] % Background is inherited already, so add behind background path: \behindbackgroundpath{% % Store lower left in xa/ya and upper right in xb/yb \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y % Top surface: \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@yb}}% Top left \pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xa}{\pgf@yb}}{\pgfqpoint{\xoffset}{\yoffset}}}% Top left plus offset vector \pgfpathlineto{\pgfpointadd{\northeast}{\pgfqpoint{\xoffset}{\yoffset}}}% Top right (northeast) plus offset vector \pgfpathlineto{\northeast} \pgfpathclose % Access current fillcolor as specified by user % Make sides darker than current fill color for some 3D effect \colorlet{currentfill}{\tikz@fillcolor} \pgfsetfillcolor{currentfill!90!black} \pgfusepath{fill, stroke} % Right surface: \pgfpathmoveto{\northeast} \pgfpathlineto{\pgfpointadd{\northeast}{\pgfqpoint{\xoffset}{\yoffset}}}% Top right corner plus offset vector \pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@ya}}{\pgfqpoint{\xoffset}{\yoffset}}}% Bottom right corner plus offset vector \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}% Bottom right corner \pgfpathclose \pgfsetfillcolor{currentfill!80!black}% Even darker than top surface \pgfusepath{fill, stroke} % Draw an ellipse to fake a thermostat or pipe exit. % Position it at 0.8 / 80% height % Ellipse axes are confusing and I did not do it properly fully \pgfpathellipse{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@ya + 0.8*(\pgf@yb - \pgf@ya)}}{\pgfpointscale{0.5}{\pgfqpoint{\xoffset}{\yoffset}}}}{\pgfpoint{0.2*\xoffset}{0.2*\yoffset}}{\pgfpoint{0pt}{1pt}} \pgfsetfillcolor{black} \pgfusepath{fill} } % Background is already the inherited rectangle. Draw on top of it with beforebackgroundpath \beforebackgroundpath{ % Store lower left in xa/ya and upper right in xb/yb \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y % Draw vertical lines on top of front surface: \foreach \posfraction in {0.2, 0.4, ..., 0.8}{ \pgfpathmoveto{\pgfpoint{\pgf@xa + \posfraction*(\pgf@xb - \pgf@xa)}{\pgf@ya + 0.2*(\pgf@yb - \pgf@ya)}} \pgfpathlineto{\pgfpoint{\pgf@xa + \posfraction*(\pgf@xb - \pgf@xa)}{\pgf@ya + 0.8*(\pgf@yb - \pgf@ya)}} \pgfusepath{stroke} } } } \pgfdeclareshape{vented radiator}{ \inheritsavedanchors[from=radiator]% Inherit from rectangle, should be good enough. Rectangle has to 'saved anchors': southwest and northeast \inheritanchorborder[from=radiator] % Doesn't hurt to also inherit specific anchors: \inheritanchor[from=radiator]{north} \inheritanchor[from=radiator]{north west} \inheritanchor[from=radiator]{north east} \inheritanchor[from=radiator]{center} \inheritanchor[from=radiator]{west} \inheritanchor[from=radiator]{east} \inheritanchor[from=radiator]{mid} \inheritanchor[from=radiator]{mid west} \inheritanchor[from=radiator]{mid east} \inheritanchor[from=radiator]{base} \inheritanchor[from=radiator]{base west} \inheritanchor[from=radiator]{base east} \inheritanchor[from=radiator]{south} \inheritanchor[from=radiator]{south west} \inheritanchor[from=radiator]{south east} % Inherit our special nodes: \inheritanchor[from=radiator]{right} \inheritanchor[from=radiator]{top} \inheritanchor[from=radiator]{exit} \inheritanchor[from=radiator]{lower entry} \inheritanchor[from=radiator]{upper entry} % Inherit all stuff from base radiator: \inheritbackgroundpath[from={radiator}] \inheritbehindbackgroundpath[from={radiator}] \inheritbeforebackgroundpath[from={radiator}] % Anchor for the ventilation point. % I tried with \savedanchor, but it didn't work so we have to repeat the calculations for the ventilation device \anchor{ventilation}{% \southwest \pgf@xa=\pgf@x \northeast \pgf@yb=\pgf@y \pgfmathsetlength\pgf@x{\pgf@xa - 3pt} \pgfmathsetlength\pgf@y{\pgf@yb - 3pt} } \behindforegroundpath{ \southwest \pgf@xa=\pgf@x \northeast \pgf@yb=\pgf@y \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@yb}}% Top left corner \pgfpatharc{90}{270}{3pt}% Arc from top-top left corner down with specified radius in last argument \pgfsetfillcolor{black} \pgfusepath{fill} } } \pgfdeclareshape{sensor}{ \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough. Rectangle has to 'saved anchors': southwest and northeast \inheritanchorborder[from=rectangle] % Doesn't hurt to also inherit specific anchors: \inheritanchor[from=rectangle]{north} \inheritanchor[from=rectangle]{north west} \inheritanchor[from=rectangle]{north east} \inheritanchor[from=rectangle]{center} \inheritanchor[from=rectangle]{west} \inheritanchor[from=rectangle]{east} \inheritanchor[from=rectangle]{south} \inheritanchor[from=rectangle]{south west} \inheritanchor[from=rectangle]{south east} \backgroundpath{ % Store lower left in xa/ya and upper right in xb/yb \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y \pgfpathmoveto{\pgfpoint{\pgf@xa + (\pgf@xb - \pgf@xa)/2}{\pgf@yb}}% Upper middle \pgfpathlineto{\pgfpoint{\pgf@xa + (\pgf@xb - \pgf@xa)/2}{\pgf@ya + 0.3*(\pgf@yb - \pgf@ya)}}% Down the middle, to 1/4 of the node height % These are percentages of the node height. % At each percentage/fraction of the height, draw a centered line with a width of a certain percentage (fractionlength) of the overall node width \foreach \fractionheight/\fractionlength in { 0.3/1,% 0.15/0.75,% 0/0.5% }{ % One horizontal line on this height: \pgfpathmoveto{\pgfpoint{\pgf@xa + (1 - \fractionlength)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya + \fractionheight*(\pgf@yb - \pgf@ya)}} \pgfpathlineto{\pgfpoint{\pgf@xb - (1 - \fractionlength)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya + \fractionheight*(\pgf@yb - \pgf@ya)}} } } } \pgfdeclareshape{levelindicator}{ \inheritsavedanchors[from=rectangle]% Inherit from rectangle, should be good enough. Rectangle has to 'saved anchors': southwest and northeast \inheritanchorborder[from=rectangle] % Doesn't hurt to also inherit specific anchors: \inheritanchor[from=rectangle]{north} \inheritanchor[from=rectangle]{north west} \inheritanchor[from=rectangle]{north east} % \inheritanchor[from=rectangle]{center} \inheritanchor[from=rectangle]{west} \inheritanchor[from=rectangle]{east} \inheritanchor[from=rectangle]{south} \inheritanchor[from=rectangle]{south west} \inheritanchor[from=rectangle]{south east} % When no other anchor is specified, nodes are placed by their 'center' anchor. % Change it here to be the lower pointy triangle bit, as opposed to the rectangle center. % That way, the triangle always points onto the fluid surface if placed as a node on a drawn line representing this surface \anchor{center}{% \southwest \pgf@xa=\pgf@x \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y % Lower pointy bit of triangle, as below: \pgfpoint{\pgf@xa + (\pgf@xb - \pgf@xa)/2}{\pgf@yb - sqrt(3)*((\pgf@xb - \pgf@xa)/2)} } \backgroundpath{ % Store lower left in xa/ya and upper right in xb/yb \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@yb}}% Upper left corner \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}% Upper right corner \pgfpathlineto{\pgfpoint{\pgf@xa + (\pgf@xb - \pgf@xa)/2}{\pgf@yb - sqrt(3)*((\pgf@xb - \pgf@xa)/2)}}% Forming an equilateral triangle \pgfpathclose % These are percentages of the node height. % At each percentage/fraction of the height, draw a centered line with a width of a certain percentage (fractionlength) of the overall node width \foreach \fractionheight/\fractionlength in { 0.3/1,% 0.15/0.75,% 0/0.5% }{ % One horizontal line on this height: \pgfpathmoveto{\pgfpoint{\pgf@xa + (1 - \fractionlength)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya + \fractionheight*(\pgf@yb - \pgf@ya)}} \pgfpathlineto{\pgfpoint{\pgf@xb - (1 - \fractionlength)/2*(\pgf@xb - \pgf@xa)}{\pgf@ya + \fractionheight*(\pgf@yb - \pgf@ya)}} } } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Scientifics Typesetting %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{chemmacros}% \ch{}, \chcpd[]{compound} etc. \chemsetup{% formula=chemformula,% chemformula/font-family=tgpl,% Use math font family } % Some new custom environments. Very simple definitions that behave just like the % widely known AMSMath math environment as specified in the last argument. \NewChemReaction{reactionsgather}{gather}% Like AMSmath's `gather` \NewChemReaction{reactionsgather*}{gather*} % Sort reaction counter underneath chapter, see % https://tex.stackexchange.com/questions/530210/how-to-cross-reference-reactions-in-chemmacros-chapter#comment1340793_530210 \renewcommand*{\thereaction}{\thechapter.\arabic{reaction}} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{siunitx}% Typesetting physical units correctly \sisetup{% % For siunitx v3, the following block replaces what used to be % `detect-all` (removed in that release, see % https://github.com/josephwright/siunitx/blob/main/CHANGELOG.md#v300 ). % It allows the `siunitx` output to match surrounding text/math (italics/bold/..., % roman/sans/... etc. as much as possible) mode=match, propagate-math-font=true, reset-math-version=false, reset-text-family=false, reset-text-series=false, reset-text-shape=false,% Not part of official fix, but still added (see https://collaborating.tuhh.de/alex/latex-cookbook/-/issues/8) text-family-to-math=true, text-series-to-math=true, % % Requires siunitx v3+, see also https://tex.stackexchange.com/a/468031/120853, % https://github.com/josephwright/siunitx/issues/532 : text-font-command=\unitnumberfont, % % Alternative range-phrase: % en-dash via '--', but inside \text{}, so it's not 'two minus signs' % range-phrase={\,\text{--}\,}, range-units=single,% single: Print unit only once, at end per-mode=symbol, }% % Second setup step, with locales. See also % https://tex.stackexchange.com/a/46979/120853 \gappto{\blockextras@german}{% \sisetup{locale=DE} } \gappto{\blockextras@english}{% \sisetup{locale=US} } % Declare units ourselves: % Set as text so it stays a hyphen in math mode, as opposed to minus sign \DeclareSIUnit{\volpercent}{Vol.\text{-}\%} \DeclareSIUnit{\watthour}{Wh}% \DeclareSIUnit{\annum}{a}% \DeclareSIUnit{\atmosphere}{atm}% \DeclareSIUnit{\partspermillion}{ppm}% \DeclareSIUnit{\bar}{bar}% https://tex.stackexchange.com/a/598473/120853 % Unit qualifiers, i.e. subscripts. % We already have a dedicated system (bib file with glossaries-extra) for subscripts % for symbols, so use those (just format, don't index) also for units here. \DeclareSIQualifier{\dryair}{% for moist air context \glsfmtname{sub.dry}\glsfmtname{sub.air}% } \DeclareSIQualifier{\water}{% \glsfmtname{sub.water}% } \DeclareSIQualifier{\thermal}{% \glsfmtname{sub.thermal}% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Hyperref and PDFs appearance %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage[pdfusetitle]{hyperref}% Loads url-package internally \hypersetup{% % Unicode settings are automatically true for luatex engine, % don't specify manually colorlinks=true,% No ugly frames, but still colored allcolors=darklink,% % hidelinks,% Toggle here! plainpages=false,% pdfsubject={% Comprehensive LaTeX template with examples for theses, books and more, employing the 'latest and greatest'. }, pdfkeywords={% latex,% template,% modern,% thesis,% phd,% master,% bachelor,% best practices,% }, pdfcreator={% LaTeX with hyperref, glossaries-extra/bib2gls and biblatex/biber [\GitRefName{}@\GitShortSHA{}]% }, bookmarksnumbered=true,% % Default opening of the document in supported PDF viewers: pdfpagelayout=TwoPageRight, pdfdisplaydoctitle,% https://tex.stackexchange.com/a/435434/120853 }% % In order to translate, polyglossia wraps things into \text, e.g. % \textenglish. If this is part of a PDF string, like when we do % \addchap{\glossaryname}, LaTeX/hyperref will complain that \textenglish is not a % PDF string and is dropped. % Therefore, disable commands of the form \text in this document. Don't % use a static language but the current language from kvoptions. % % Expansion works as follows: % \expandafter is executed, causing \let to be saved for later. % \csname is then executed next. It scans ahead to its matching \endcsname, % "performing full expansion as it goes" (Quote from % https://tex.stackexchange.com/a/430557/120853). % In that process, \acp@language is expanded to the value it was given in the % document options through kvoptions. % Now, \csname finishes and presents a token \text, e.g. \textenglish. % LaTeX starts over; \expandafter is now gone, so it reads \let\text ... % In this case, ... is \relax, removing the macro definition. % It will no longer occur in PDF commands. % See also: % https://www.overleaf.com/learn/latex/Articles/How_does_%5Cexpandafter_work:_A_detailed_study_of_consecutive_%5Cexpandafter_commands % and % TUGboat, Volume 9, 1988, No. 1: Macros: A Tutorial on \expandafter by % Stephan v. Bechtolsheim. % % Idea from https://tex.stackexchange.com/a/230197/120853 \pdfstringdefDisableCommands{% \expandafter\let\csname text\acp@language\endcsname \relax% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Appearance of the bookmarks popup in viewers that support it %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{bookmark}% Control bookmark appearance in PDF \bookmarksetup{% open,% Open bookmark pane in PDF viewer openlevel=1,% Open first two levels, hide all subsections etc. (0-indexed) addtohook={% \ifnum\bookmarkget{level}=0% Only print top-level (0) bookmarks bold \bookmarksetup{bold}% \fi% },% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Glossaries %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage[% Initiate with package options for predefined styles nomain,% Nomain, aka no default glossary record,% Record usages of commands to auxiliary files for bib2gls abbreviations,% Regular abbreviations/acronyms symbols,% Physical symbols index,% A regular book index at the end numbers,% constants like Pi toc=true,% Toggle inclusion in Table of Contents ]{glossaries-extra}% Also see https://tex.stackexchange.com/q/477658/120853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % New Glossary 'types' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Using Abbreviations/Symbols etc. package options creates these glossaries already. % Create the rest manually. \newglossary*{subscripts}{\TransSubscripts{}}% % For example, in the case of symbols, there are three groups: roman, greek and % other. % If the 'other' sub-glossary is used (it provides the built-ins like % \mean, \vect, \deriv, ...) but is NOT supposed to be printed in the PDF glossary, % it is assigned to the following glossary type. % The glossary is printed using \printunsrtglossary with a `type=` % keyword specified, which would also print the 'other' entries, since they are of % type 'symbols' as well. Only by assigning a different type altogether is this % circumvented. This does not impact using the commands and the defined entries using % \sym{}, since that is provided by the 'label-prefix', not the 'type'. % Analogue procedures apply to all glossaries. \newglossary*{notprinted}{Non-printed entries}% Title never occurs anyway! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % New Glossary 'fields' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Add custom key for a 'unit' field for symbols: \glsaddkey{unit}% {\relax}% {\glsentryunit}% {\Glsentryunit}% {\glsunit}% {\Glsunit}% {\GLSunit} % For specific quantities (enthalpy etc.) \glsaddkey{specific}% {\relax}% {\glsentryspecific}% {\Glsentryspecific}% {\glsspecific}% {\Glsspecific}% {\GLSspecific} % For First names of people \glsaddkey{firstname}% {\relax}% {\glsentryfirstname}% {\Glsentryfirstname}% {\glsfirstname}% {\Glsfirstname}% {\GLSfirstname} % For values of numbers/constants \glsaddkey{value}% {\relax}% {\glsentryvalue}% {\Glsentryvalue}% {\glsvalue}% {\Glsvalue}% {\GLSvalue} % For international versions of symbols \glsaddkey{international-symbol}% {\relax}% {\glsentryinternationalsymbol}% {\Glsentryinternationalsymbol}% {\glsinternationalsymbol}% {\Glsinternationalsymbol}% {\GLSinternationalsymbol} % For alternative versions of symbols \glsaddkey{alternative-symbol}% {\relax}% {\glsentryalternativesymbol}% {\Glsentryalternativesymbol}% {\glsalternativesymbol}% {\Glsalternativesymbol}% {\GLSalternativesymbol} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Abstract the prefixes here. % For example, if we load 'symbols' from a 'roman' file, % we define a prefix and call entries later as \gls{.} % These prefixes are used in various places; define them here once and reference later %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newcommand*{\symprefix}{sym.} \newcommand*{\subprefix}{sub.} \newcommand*{\nameprefix}{name.} \newcommand*{\constantsprefix}{cons.} \newcommand*{\indexprefix}{idx.} \newcommand*{\abbreviationprefix}{abb.} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Load the bib files: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \GlsXtrLoadResources[% src={bib/glossaries/abbreviations},% sort=doc,% Use document language for sorting label-prefix={\abbreviationprefix}, type=abbreviations, selection={all},% ]% \GlsXtrLoadResources[% src={bib/glossaries/index/terms},% sort=doc, % Use document language for sorting type=index, group=terms, label-prefix={\indexprefix}, selection={all},% ]% \GlsXtrLoadResources[% src={bib/glossaries/index/names},% sort=doc, % Use document language for sorting type=index, category=names, group=names, label-prefix={\nameprefix}, selection={all},% ]% \GlsXtrLoadResources[% src={bib/glossaries/symbols/roman},% sort=doc, % Use document language for sorting symbol-sort-fallback=name,% Sort by name aka symbol if sort field is missing % % If first field is equal, sort by this next (by appending it). % E.g. 'c' for 'Velocity' and also for 'Heat Capacity' is then sorted with % 'Heat Capacity' first etc.: sort-suffix=description, label-prefix={\symprefix}, type=symbols,% Change this to 'notprinted' to omit printing in the glossary category={same as type}, selection={all}, group={roman}, ]% \GlsXtrLoadResources[% src={bib/glossaries/symbols/greek},% sort=doc, % Use document language for sorting symbol-sort-fallback=name,% Sort by name aka symbol if sort field is missing % % If first field is equal, sort by this next (by appending it). % E.g. 'c' for 'Velocity' and also for 'Heat Capacity' is then sorted with % 'Heat Capacity' first etc.: sort-suffix=description, label-prefix={\symprefix}, type=symbols,% Change this to 'notprinted' to omit printing in the glossary category={same as type}, selection={all}, group={greek}, ]% \GlsXtrLoadResources[% src={bib/glossaries/symbols/other},% sort=doc, % Use document language for sorting symbol-sort-fallback=name,% Sort by name aka symbol if sort field is missing % % If first field is equal, sort by this next (by appending it). % E.g. 'c' for 'Velocity' and also for 'Heat Capacity' is then sorted with % 'Heat Capacity' first etc.: sort-suffix=description, label-prefix={\symprefix}, type=symbols,% Change this to 'notprinted' to omit printing in the glossary category={same as type}, selection={all}, group={other}, ]% \GlsXtrLoadResources[% src={bib/glossaries/symbols/subscripts},% % sort=doc, % Use document language for sorting sort-field=name,% Default is by label, not by name type=subscripts,% category=subscripts, label-prefix={\subprefix}, selection={all},% ]% \GlsXtrLoadResources[ src={bib/glossaries/constants},% constants.bib type={numbers},% set the type for all selected entries category={number},% set the category for all selected entries label-prefix={\constantsprefix}, ] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Introduce new commands that alias \gls commands and allow modifiers % You then use e.g. \sym{velocity} to access \gls{sym.velocity} etc. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \glsxtrnewgls{\symprefix}{\sym}% \sym{XYZ} is like \gls{sym.XYZ} \glsxtrnewgls{\subprefix}{\sub} \glsxtrnewgls{\nameprefix}{\name} \glsxtrnewgls{\constantsprefix}{\cons} \glsxtrnewgls{\indexprefix}{\idx} \glsxtrnewgls{\abbreviationprefix}{\abb} % We cannot alias the commands introduced by `\glsaddkey` the same way: % \glsxtrnewgls only works on \gls{.} to alias the away % into its own command. However, for a command like \glsspecific{}, it does not work. % We can therefore do \sym{volume}, but have to do \glsspecific{sym.volume}, i.e. % specify the prefix manually. % A short-cut command is therefore enabled by the following commands. \newcommand*{\symspec}[2][]{\glsspecific[#1]{\symprefix#2}} % Register with glossaries-extra so it writes info to aux file: \glsxtridentifyglslike{\symprefix}{\symspec} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Further Options: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % indexonlyfirst can also be a package option. % Index only on first use for certain categories, as set manually above. % https://tex.stackexchange.com/a/318886/120853 % \glssetcategoryattribute{symbols}{indexonlyfirst}{true} % \glssetcategoryattribute{subscripts}{indexonlyfirst}{true} \glssetcategoryattribute{names}{textformat}{textsc} % As printed in the text \glssetcategoryattribute{names}{glossnamefont}{textsc} % As printed in the Glossary \newcommand*{\specificsymbolmark}{*} % \glsdefpostdesc{symbols}{% If entry has field 'specific', its description is marked \ifglshasfield{specific}{\glscurrententrylabel}% {\specificsymbolmark}% {}% } % Append stuff after 'name' field for the 'symbols' category. % Syntax: \ifglshasfield{}{