commit 3060d61279e908774d6d421e0de4a2aacfe03c47 Author: Peter Adam Date: Tue Feb 3 13:46:49 2026 +0100 Initial commit: Brevet card LaTeX sources Add LaTeX templates for 200km brevet cards with front and back sides. Includes Docker-based build system and documentation. Co-Authored-By: Claude Sonnet 4.5 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96bfe5b --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# LaTeX build artifacts +*.aux +*.log +*.out +*.toc +*.synctex.gz +*.fls +*.fdb_latexmk + +# Rendered PDFs +*.pdf + +# macOS +.DS_Store + +# Editor files +*.swp +*.swo +*~ +.vscode/ +.idea/ + +# Claude Code +.claude/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f92184c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM texlive/texlive:latest + +# Install additional packages if needed +RUN apt-get update && apt-get install -y \ + make \ + && rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /workspace + +# Copy project files +COPY brevetkarte.tex . +COPY cyclist-logo.png . + +# Default command +CMD ["pdflatex", "-interaction=nonstopmode", "brevetkarte.tex"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8220941 --- /dev/null +++ b/Makefile @@ -0,0 +1,85 @@ +# Makefile for building Brevet card PDF in Docker + +IMAGE_NAME := brevetcard-builder +CONTAINER_NAME := brevetcard-build +TEX_FILE_FRONT := brevetkarte.tex +TEX_FILE_BACK := brevetkarte-rueckseite.tex +PDF_FILE_FRONT := brevetkarte.pdf +PDF_FILE_BACK := brevetkarte-rueckseite.pdf + +.PHONY: all build clean build-image build-pdf build-front build-back run shell help + +# Default target +all: build + +# Build both PDFs (builds image if needed, then compiles) +build: build-image build-front build-back + +# Build Docker image +build-image: + @echo "Building Docker image..." + docker build -t $(IMAGE_NAME) . + +# Compile both PDFs in Docker container +build-pdf: build-front build-back + +# Compile front side PDF +build-front: + @echo "Compiling front side LaTeX to PDF..." + docker run --rm \ + -v $(PWD):/workspace \ + $(IMAGE_NAME) \ + pdflatex -interaction=nonstopmode $(TEX_FILE_FRONT) + @echo "PDF generated: $(PDF_FILE_FRONT)" + +# Compile back side PDF +build-back: + @echo "Compiling back side LaTeX to PDF..." + docker run --rm \ + -v $(PWD):/workspace \ + $(IMAGE_NAME) \ + pdflatex -interaction=nonstopmode $(TEX_FILE_BACK) + @echo "PDF generated: $(PDF_FILE_BACK)" + +# Run container interactively +run: + docker run --rm -it \ + -v $(PWD):/workspace \ + $(IMAGE_NAME) \ + /bin/bash + +# Open shell in container for debugging +shell: + docker run --rm -it \ + -v $(PWD):/workspace \ + --entrypoint /bin/bash \ + $(IMAGE_NAME) + +# Clean generated files +clean: + @echo "Cleaning generated files..." + rm -f *.aux *.log *.out *.toc *.pdf + +# Clean everything including Docker image +clean-all: clean + @echo "Removing Docker image..." + docker rmi $(IMAGE_NAME) 2>/dev/null || true + +# Rebuild from scratch +rebuild: clean-all build + +# Show help +help: + @echo "Brevet Card PDF Builder" + @echo "" + @echo "Available targets:" + @echo " make build - Build Docker image and compile both PDFs (default)" + @echo " make build-image - Build Docker image only" + @echo " make build-pdf - Compile both front and back PDFs" + @echo " make build-front - Compile front side PDF only" + @echo " make build-back - Compile back side PDF only" + @echo " make shell - Open interactive shell in container" + @echo " make clean - Remove generated files (aux, log, pdf)" + @echo " make clean-all - Remove all files and Docker image" + @echo " make rebuild - Clean everything and rebuild" + @echo " make help - Show this help message" diff --git a/README.md b/README.md new file mode 100644 index 0000000..494fde3 --- /dev/null +++ b/README.md @@ -0,0 +1,124 @@ +# Brevet Card PDF Generator + +LaTeX-based generator for Audax Randonneurs Deutschland brevet cards with front and back sides for duplex printing. + +## Quick Start + +```bash +# Build everything and generate both PDFs +make build + +# The PDFs will be created as: +# - brevetkarte.pdf (front side with participant info) +# - brevetkarte-rueckseite.pdf (back side with control points) +``` + +## Prerequisites + +- Docker +- Make + +## Usage + +### Build Both PDFs +```bash +make build +``` + +This will: +1. Build the Docker image with TeXLive +2. Compile `brevetkarte.tex` to `brevetkarte.pdf` (front side) +3. Compile `brevetkarte-rueckseite.tex` to `brevetkarte-rueckseite.pdf` (back side) + +### Build Individual Sides + +```bash +# Just build front side +make build-front + +# Just build back side +make build-back + +# Build both sides (without rebuilding Docker image) +make build-pdf +``` + +### Other Commands + +```bash +# Just build the Docker image +make build-image + +# Open interactive shell in container +make shell + +# Clean generated files (.aux, .log, .pdf) +make clean + +# Clean everything including Docker image +make clean-all + +# Rebuild from scratch +make rebuild + +# Show help +make help +``` + +## Files + +- `brevetkarte.tex` - LaTeX source for the front side (participant info) +- `brevetkarte-rueckseite.tex` - LaTeX source for the back side (control points) +- `cyclist-logo.png` - Audax Randonneurs logo (extracted from original) +- `Dockerfile` - Docker image definition with TeXLive +- `Makefile` - Build automation +- `Brevet200km_2025_09_20_Namensseite_blanko.pdf` - Original front side template +- `Brevet200km_2025_09_20_Kontrollseite.pdf` - Original back side template + +## Output + +### Front Side (brevetkarte.pdf) +Contains two identical brevet cards that can be cut in half. Each card includes: +- Participant information fields (Name, Address, etc.) +- Event details (200km "Auf eine Pommes nach Belgien") +- Randonneur Mondiaux rules +- Homologation section +- Start time: 8:30 + +### Back Side (brevetkarte-rueckseite.pdf) +Contains control points table (4 columns × 6 rows): +- **Rows 1-3**: Control points for upper card + - Nr. 1: Start (Km 0 - Unisport, Bonn) + - Nr. 2: Km 57 - Nationalpark-Tor, Heimbach + - Nr. 3: Km 100 - Friterie "Au Petit Creux", Waimes + - Nr. 4: Km 165 - Mahlberg + - Nr. 5: Km 205 - Finish (Unisport, Bonn) +- **Rows 4-6**: Control points for lower card (same as above, but Nr. 5: Km 214) +- Empty columns for stamps/signatures +- Control question for verification + +## Duplex Printing + +The PDFs are designed for duplex (double-sided) printing: +1. Print `brevetkarte.pdf` on one side +2. Print `brevetkarte-rueckseite.pdf` on the reverse side +3. The columns and rows are aligned so that: + - Front side columns match back side columns + - Upper card (rows 1-3) aligns with front side upper card + - Lower card (rows 4-6) aligns with front side lower card +4. Cut the sheet in half horizontally to create two separate brevet cards + +## Customization + +Edit `brevetkarte.tex` to modify front side: +- Event name, date, and location +- Distance (200km) +- Start time +- Club information +- Brevet number format + +Edit `brevetkarte-rueckseite.tex` to modify back side: +- Control point locations +- Control times (von/bis) +- Distances +- Control questions diff --git a/brevetkarte-rueckseite.tex b/brevetkarte-rueckseite.tex new file mode 100644 index 0000000..48fd574 --- /dev/null +++ b/brevetkarte-rueckseite.tex @@ -0,0 +1,218 @@ +\documentclass[a4paper,10pt,landscape]{article} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage[landscape,top=0.8cm,bottom=0.8cm,left=0.8cm,right=0.8cm]{geometry} +\usepackage{array} +\usepackage{helvet} + +% Set sans-serif font as default +\renewcommand{\familydefault}{\sfdefault} + +\setlength{\parindent}{0pt} +\setlength{\tabcolsep}{3pt} +\pagestyle{empty} + +% A4 landscape height: 21cm +% Half height: 10.5cm from top of page +% Top margin: 0.8cm +% Row 4 should start at: 10.5 - 0.8 = 9.7cm from start of content +% +% Front side: each card is 8.5cm tall +% So rows 1-3 should be: 8.5cm total (2.833cm each) +% Gap after row 3: 9.7 - 8.5 = 1.2cm + +\newcommand{\rowheight}{2.833cm} + +\begin{document} + +% Upper card table (rows 1-3) +\noindent +\begin{tabular}{|p{6.6cm}|p{6.6cm}|p{6.6cm}|p{6.6cm}|} +\hline +% Row 1 (Upper card) - height 2.833cm +\parbox[c][\rowheight][t]{6.5cm}{% +\vspace{2mm} +\textbf{Nr. 1:} Km 0 - Unisport\\ +Nachtigallenweg 86, Bonn\\ +\\ +\textbf{Kontrollzeit}\\ +von: 7:30\\ +bis: 8:30 +} +& +\parbox[c][\rowheight][c]{6.5cm}{% +% Empty for stamps +} +& +\parbox[c][\rowheight][t]{6.5cm}{% +\vspace{2mm} +\textbf{Nr. 4:} Km 165 Mahlberg Ecke K50,\\ +Breitestraße\\ +\textbf{Kontrollzeit}\\ +von: 13:21\\ +bis: 19:30 +} +& +\parbox[c][\rowheight][t]{6.5cm}{% +\vspace{2mm} +\textbf{Kontrollfrage:}\\ +Wann wurde das Kriegerdenkmal\\ +eingerichtet? +} +\\ +\hline + +% Row 2 (Upper card) - height 2.833cm +\parbox[c][\rowheight][t]{6.5cm}{% +\vspace{2mm} +\textbf{Nr. 2:} Km 57 -- „Nationalpark-Tor" im\\ +alten Bahnhofsgebäude, Heimbach\\ +\\ +\textbf{Kontrollzeit}\\ +von: 9:11\\ +bis: 12:21 +} +& +\parbox[c][\rowheight][c]{6.5cm}{% +% Empty for stamps +} +& +\parbox[c][\rowheight][t]{6.5cm}{% +\vspace{2mm} +\textbf{Nr. 5:} Km 205 - Unisport\\ +Nachtigallenweg 86, Bonn\\ +\\ +\textbf{Kontrollzeit}\\ +von: 13:23\\ +bis: 21:00 +} +& +\parbox[c][\rowheight][c]{6.5cm}{% +% Empty +} +\\ +\hline + +% Row 3 (Upper card) - height 2.833cm +\parbox[c][\rowheight][t]{6.5cm}{% +\vspace{2mm} +\textbf{Nr. 3:} Km 100 - Friterie „Au Petit\\ +Creux" oder Total-Tankstelle, Ecke Rue\\ +de Botrange/Rue de Charmilles, Waimes\\ +\textbf{Kontrollzeit}\\ +von: 11:26\\ +bis: 15:10 +} +& +\parbox[c][\rowheight][c]{6.5cm}{% +% Empty for stamps +} +& +\parbox[c][\rowheight][c]{6.5cm}{% +% Empty +} +& +\parbox[c][\rowheight][c]{6.5cm}{% +% Empty +} +\\ +\hline +\end{tabular} + +\vspace{1.8cm} + +% Lower card table (rows 4-6) +\noindent +\begin{tabular}{|p{6.6cm}|p{6.6cm}|p{6.6cm}|p{6.6cm}|} +\hline +% Row 1 (Lower card) +\parbox[c][\rowheight][t]{6.5cm}{% +\vspace{2mm} +\textbf{Nr. 1:} Km 0 - Unisport\\ +Nachtigallenweg 86, Bonn\\ +\\ +\textbf{Kontrollzeit}\\ +von: 7:30\\ +bis: 8:30 +} +& +\parbox[c][\rowheight][c]{6.5cm}{% +% Empty for stamps +} +& +\parbox[c][\rowheight][t]{6.5cm}{% +\vspace{2mm} +\textbf{Nr. 4:} Km 165 Mahlberg Ecke K50,\\ +Breitestraße\\ +\textbf{Kontrollzeit}\\ +von: 13:21\\ +bis: 19:30 +} +& +\parbox[c][\rowheight][t]{6.5cm}{% +\vspace{2mm} +\textbf{Kontrollfrage:}\\ +Wann wurde das Kriegerdenkmal\\ +eingerichtet? +} +\\ +\hline + +% Row 2 (Lower card) - height 2.833cm +\parbox[c][\rowheight][t]{6.5cm}{% +\vspace{2mm} +\textbf{Nr. 2:} Km 57 -- „Nationalpark-Tor" im\\ +alten Bahnhofsgebäude, Heimbach\\ +\\ +\textbf{Kontrollzeit}\\ +von: 9:11\\ +bis: 12:21 +} +& +\parbox[c][\rowheight][c]{6.5cm}{% +% Empty for stamps +} +& +\parbox[c][\rowheight][t]{6.5cm}{% +\vspace{2mm} +\textbf{Nr. 5:} Km 214 - Unisport\\ +Nachtigallenweg 86, Bonn\\ +\\ +\textbf{Kontrollzeit}\\ +von: 13:23\\ +bis: 21:00 +} +& +\parbox[c][\rowheight][c]{6.5cm}{% +% Empty +} +\\ +\hline + +% Row 3 (Lower card) - height 2.833cm +\parbox[c][\rowheight][t]{6.5cm}{% +\vspace{2mm} +\textbf{Nr. 3:} Km 100 - Friterie „Au Petit\\ +Creux" oder Total-Tankstelle, Ecke Rue\\ +de Botrange/Rue de Charmilles, Waimes\\ +\textbf{Kontrollzeit}\\ +von: 11:26\\ +bis: 15:10 +} +& +\parbox[c][\rowheight][c]{6.5cm}{% +% Empty for stamps +} +& +\parbox[c][\rowheight][c]{6.5cm}{% +% Empty +} +& +\parbox[c][\rowheight][c]{6.5cm}{% +% Empty +} +\\ +\hline +\end{tabular} + +\end{document} diff --git a/brevetkarte.tex b/brevetkarte.tex new file mode 100644 index 0000000..70a2ef3 --- /dev/null +++ b/brevetkarte.tex @@ -0,0 +1,138 @@ +\documentclass[a4paper,10pt,landscape]{article} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage[landscape,top=0.8cm,bottom=0.8cm,left=0.8cm,right=0.8cm]{geometry} +\usepackage{graphicx} +\usepackage{xcolor} +\usepackage{tikz} +\usepackage{helvet} +\usepackage{hyperref} +\usepackage{enumitem} + +% Set sans-serif font as default +\renewcommand{\familydefault}{\sfdefault} + +% Define colors +\definecolor{headerblack}{RGB}{0,0,0} + +% Configure hyperlinks to be black +\hypersetup{ + colorlinks=true, + linkcolor=black, + urlcolor=black, + citecolor=black +} + +\setlength{\parindent}{0pt} +\pagestyle{empty} + +% Command to create one brevet card +\newcommand{\brevetcard}{% +\noindent +\begin{tikzpicture}[x=1cm,y=1cm] + +% Black vertical separator lines (drawn first, extend through headers) +\draw[black,line width=0.5pt] (6.9,-7.2) -- (6.9,1.3); +\draw[black,line width=0.5pt] (13.8,-7.2) -- (13.8,1.3); +\draw[black,line width=0.5pt] (20.7,-7.2) -- (20.7,1.3); + +% Black header boxes (drawn on top) +\fill[headerblack] (0,0) rectangle (6.9,1.3); +\node[white,align=center,font=\tiny,text width=6.6cm] at (3.45,0.65) { + Jeder Teilnehmer muss diese Brevetkarte zu jeder Zeit\\ + mit sich führen und an den Kontrollen abstempeln lassen\\ + bzw. Fotos erstellen.\\ + \textbf{Ohne Kontrollzeiten und Zielzeit keine Wertung!} +}; + +\fill[headerblack] (6.9,0) rectangle (13.8,1.3); +\node[white,font=\Large] at (10.35,0.65) {HOMOLOGATION}; + +\fill[headerblack] (13.8,0) rectangle (20.7,1.3); +\node[white,font=\Large] at (17.25,0.65) {TEILNEHMER/-IN}; + +\fill[headerblack] (20.7,0) rectangle (27.6,1.3); +\node[white,align=center,font=\normalsize] at (24.15,0.75) {BREVET DES RANDONNEURS}; +\node[white,font=\Large] at (24.15,0.35) {MONDIAUX}; + +% Column 1 - Rules (left section) +\node[anchor=north west,text width=6.6cm,font=\small,align=left] at (0.2,-0.3) { + \textbf{Es gelten die Regeln von}\\ + \textbf{Randonneur Mondiaux}\\ + \textbf{insbesondere:} + \begin{itemize}[leftmargin=0.4cm,itemsep=1pt,topsep=2pt,parsep=0pt] + \item Einhaltung der StVO + \item Beleuchtung und Sicherheitsweste/-Gurt + \item keine Abkürzungen + \item keine Begleitfahrzeuge + \item Rücksicht auf Teilnehmer und Umwelt + \item Rücksicht in den Kontrollen + \end{itemize} + \hspace{0.3cm}$\Rightarrow$ \textbf{\underline{Bei Verstoß keine Wertung!}}\\[0.3cm] + - +}; + +\node[anchor=south west,text width=6.6cm,font=\small,align=left] at (0.2,-7.0) { + \textbf{AUDAX RANDONNEURS ALLEMAGNE E.V.}\\ + \href{http://www.audax-randonneure.de}{www.audax-randonneure.de}\\ + - gegründet 1992 in Hamburg - +}; + +% Column 2 - Homologation (middle-left section) +\node[anchor=north,text width=6.6cm,font=\small,align=center] at (10.35,-0.5) { + Der Randonnée wurde beendet in:\\[0.6cm] + \makebox[2cm]{\dotfill}h\makebox[2cm]{\dotfill}min +}; + +\node[anchor=center,font=\Large] at (10.35,-4.0) { + HOMOLOGATION +}; + +\node[anchor=south,text width=6.6cm,font=\small,align=center] at (10.35,-6.8) { + Brevet N° \makebox[5cm]{\dotfill} +}; + +% Column 3 - Participant Info (middle-right section) +\node[anchor=north west,text width=6.6cm,font=\small,align=left] at (14.0,-0.5) { + Name:\\[0.4cm] + Straße:\\[0.4cm] + PLZ/Ort:\\[0.4cm] + Land:\\[0.4cm] + Medaille:\\[0.6cm] + Startzeit: 8:30 +}; + +% Column 4 - Event Info (right section) +\node[anchor=north,text width=6.6cm,align=center] at (24.15,-0.4) { + \includegraphics[width=5.5cm]{cyclist-logo.png} +}; + +\node[anchor=north,text width=6.6cm,font=\small,align=center] at (24.15,-2.2) { + \textbf{Auf eine Pommes nach Belgien}\\ + Randonnée über \textbf{200} km\\ + am \textbf{20. September 2025}\\ + mit Start in \textbf{Bonn, Uni-Sportgelände}\\ + von \textbf{ARA Rheinland}\\ + N° ACP du Club \textbf{111011} +}; + +\node[anchor=south,text width=6.6cm,font=\scriptsize,align=center] at (24.15,-7.0) { + CONTRÔLÉE ET HOMOLOGUÉE EXCLUSIVEMENT PAR\\ + \href{http://www.audax-club-parisien.com}{www.audax-club-parisien.com}\\ + - Société fondée en 1904 - +}; + +\end{tikzpicture} +} + +\begin{document} + +% First brevet card +\brevetcard + +\vspace{0.8cm} + +% Second brevet card (identical) +\brevetcard + +\end{document} diff --git a/cyclist-logo.png b/cyclist-logo.png new file mode 100644 index 0000000..f3b0c43 Binary files /dev/null and b/cyclist-logo.png differ