Compare commits
10 Commits
74269c4fbb
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| ca995a1c1f | |||
| f811c3fd80 | |||
| 0c4d630d8e | |||
| b22f1f74a8 | |||
| f2eda5bf43 | |||
| a2b5c6dc4a | |||
| 331e6e70a9 | |||
| 9b42f824f9 | |||
| c40fe447b0 | |||
| 82deb5ac15 |
+4
-2
@@ -11,14 +11,16 @@
|
|||||||
*.pdf
|
*.pdf
|
||||||
*.bak
|
*.bak
|
||||||
|
|
||||||
# Real participant data (copy to "Export Brevetkarte.csv" and fill in)
|
# Real participant data (copy export_brevetcard.csv.example and fill in)
|
||||||
Export Brevetkarte.csv
|
export_brevetcard.csv
|
||||||
|
|
||||||
# Real event data (copy event.yml.example to event.yml and fill in)
|
# Real event data (copy event.yml.example to event.yml and fill in)
|
||||||
event.yml
|
event.yml
|
||||||
|
|
||||||
# Generated files
|
# Generated files
|
||||||
brevetkarte-personalized.tex
|
brevetkarte-personalized.tex
|
||||||
|
brevetkarte-blanko.tex
|
||||||
|
brevetkarte-rueckseite.tex
|
||||||
|
|
||||||
# macOS
|
# macOS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
+3
-8
@@ -5,14 +5,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
texlive-pictures \
|
texlive-pictures \
|
||||||
texlive-fonts-recommended \
|
texlive-fonts-recommended \
|
||||||
make \
|
make \
|
||||||
|
python3 \
|
||||||
|
python3-yaml \
|
||||||
|
pdftk-java \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Set working directory
|
|
||||||
WORKDIR /workspace
|
WORKDIR /workspace
|
||||||
|
|
||||||
# Copy project files
|
|
||||||
COPY brevetkarte.tex .
|
|
||||||
COPY cyclist-logo.png .
|
|
||||||
|
|
||||||
# Default command
|
|
||||||
CMD ["pdflatex", "-interaction=nonstopmode", "brevetkarte.tex"]
|
|
||||||
|
|||||||
@@ -1,37 +1,27 @@
|
|||||||
# Makefile for building Brevet card PDF in Docker
|
# Makefile for building Brevet card PDF in Docker
|
||||||
|
|
||||||
IMAGE_NAME := brevetcard-builder
|
IMAGE_NAME := brevetcard-builder
|
||||||
TEX_FILE_FRONT := brevetkarte.tex
|
|
||||||
TEX_FILE_BACK := brevetkarte-rueckseite.tex
|
|
||||||
TEX_FILE_PERSONALIZED := brevetkarte-personalized.tex
|
TEX_FILE_PERSONALIZED := brevetkarte-personalized.tex
|
||||||
PDF_FILE_FRONT := brevetkarte.pdf
|
TEX_FILE_BLANKO := brevetkarte-blanko.tex
|
||||||
PDF_FILE_BACK := brevetkarte-rueckseite.pdf
|
TEX_FILE_BACK := brevetkarte-rueckseite.tex
|
||||||
PDF_FILE_PERSONALIZED := brevetkarte-personalized.pdf
|
PDF_FILE_PERSONALIZED := brevetkarte-personalized.pdf
|
||||||
CSV_FILE := Export Brevetkarte.csv
|
PDF_FILE_BLANKO := brevetkarte-blanko.pdf
|
||||||
|
PDF_FILE_BACK := brevetkarte-rueckseite.pdf
|
||||||
|
PDF_FILE_DUPLEX := brevetkarte-duplex.pdf
|
||||||
|
PDF_FILE_BLANKO_DUPLEX := brevetkarte-blanko-duplex.pdf
|
||||||
|
CSV_FILE := export_brevetcard.csv
|
||||||
|
|
||||||
.PHONY: all build clean build-image build-front build-back generate build-personalized run shell help
|
.PHONY: all build clean build-image build-back generate build-personalized build-blanko build-duplex build-blanko-duplex run shell help
|
||||||
|
|
||||||
# Default target
|
# Default target
|
||||||
all: build
|
all: build-personalized build-blanko
|
||||||
|
|
||||||
# Build static demo front side (builds image if needed)
|
|
||||||
build: build-image build-front
|
|
||||||
|
|
||||||
# Build Docker image
|
# Build Docker image
|
||||||
build-image:
|
build-image:
|
||||||
@echo "Building Docker image..."
|
@echo "Building Docker image..."
|
||||||
docker build -t $(IMAGE_NAME) .
|
docker build -t $(IMAGE_NAME) .
|
||||||
|
|
||||||
# Compile static demo front side PDF
|
# Compile back side PDF (after generate)
|
||||||
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 (always generated from event.yml via generate)
|
|
||||||
build-back: build-image
|
build-back: build-image
|
||||||
@echo "Compiling back side LaTeX to PDF..."
|
@echo "Compiling back side LaTeX to PDF..."
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
@@ -41,13 +31,16 @@ build-back: build-image
|
|||||||
@echo "PDF generated: $(PDF_FILE_BACK)"
|
@echo "PDF generated: $(PDF_FILE_BACK)"
|
||||||
|
|
||||||
# Generate all tex files from CSV + event.yml
|
# Generate all tex files from CSV + event.yml
|
||||||
generate:
|
generate: build-image
|
||||||
@echo "Generating cards from $(CSV_FILE) + event.yml..."
|
@echo "Generating cards from $(CSV_FILE) + event.yml..."
|
||||||
@if [ ! -f "$(CSV_FILE)" ]; then \
|
@if [ ! -f "$(CSV_FILE)" ]; then \
|
||||||
echo "Error: $(CSV_FILE) not found!"; \
|
echo "Error: $(CSV_FILE) not found!"; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
python3 generate_cards.py
|
docker run --rm \
|
||||||
|
-v $(PWD):/workspace \
|
||||||
|
$(IMAGE_NAME) \
|
||||||
|
python3 generate_cards.py
|
||||||
|
|
||||||
# Build personalized front + event back side PDFs
|
# Build personalized front + event back side PDFs
|
||||||
build-personalized: generate build-image
|
build-personalized: generate build-image
|
||||||
@@ -64,6 +57,44 @@ build-personalized: generate build-image
|
|||||||
pdflatex -interaction=nonstopmode $(TEX_FILE_BACK)
|
pdflatex -interaction=nonstopmode $(TEX_FILE_BACK)
|
||||||
@echo "PDF generated: $(PDF_FILE_BACK)"
|
@echo "PDF generated: $(PDF_FILE_BACK)"
|
||||||
|
|
||||||
|
# Build blank (blanko) front + event back side PDFs (no CSV required)
|
||||||
|
build-blanko: build-image
|
||||||
|
@echo "Generating blank card..."
|
||||||
|
docker run --rm \
|
||||||
|
-v $(PWD):/workspace \
|
||||||
|
$(IMAGE_NAME) \
|
||||||
|
python3 generate_cards.py --blanko
|
||||||
|
@echo "Compiling blank front side to PDF..."
|
||||||
|
docker run --rm \
|
||||||
|
-v $(PWD):/workspace \
|
||||||
|
$(IMAGE_NAME) \
|
||||||
|
pdflatex -interaction=nonstopmode $(TEX_FILE_BLANKO)
|
||||||
|
@echo "PDF generated: $(PDF_FILE_BLANKO)"
|
||||||
|
@echo "Compiling back side to PDF..."
|
||||||
|
docker run --rm \
|
||||||
|
-v $(PWD):/workspace \
|
||||||
|
$(IMAGE_NAME) \
|
||||||
|
pdflatex -interaction=nonstopmode $(TEX_FILE_BACK)
|
||||||
|
@echo "PDF generated: $(PDF_FILE_BACK)"
|
||||||
|
|
||||||
|
# Build duplex PDF (personalized front + back interleaved for duplex printing)
|
||||||
|
build-duplex: build-personalized
|
||||||
|
@echo "Combining front and back for duplex printing..."
|
||||||
|
docker run --rm \
|
||||||
|
-v $(PWD):/workspace \
|
||||||
|
$(IMAGE_NAME) \
|
||||||
|
pdftk A=$(PDF_FILE_PERSONALIZED) B=$(PDF_FILE_BACK) shuffle A B output $(PDF_FILE_DUPLEX)
|
||||||
|
@echo "PDF generated: $(PDF_FILE_DUPLEX)"
|
||||||
|
|
||||||
|
# Build duplex PDF (blank front + back interleaved for duplex printing)
|
||||||
|
build-blanko-duplex: build-blanko
|
||||||
|
@echo "Combining blank front and back for duplex printing..."
|
||||||
|
docker run --rm \
|
||||||
|
-v $(PWD):/workspace \
|
||||||
|
$(IMAGE_NAME) \
|
||||||
|
pdftk A=$(PDF_FILE_BLANKO) B=$(PDF_FILE_BACK) shuffle A B output $(PDF_FILE_BLANKO_DUPLEX)
|
||||||
|
@echo "PDF generated: $(PDF_FILE_BLANKO_DUPLEX)"
|
||||||
|
|
||||||
# Run container interactively
|
# Run container interactively
|
||||||
run:
|
run:
|
||||||
docker run --rm -it \
|
docker run --rm -it \
|
||||||
@@ -81,7 +112,7 @@ shell:
|
|||||||
# Clean generated files
|
# Clean generated files
|
||||||
clean:
|
clean:
|
||||||
@echo "Cleaning generated files..."
|
@echo "Cleaning generated files..."
|
||||||
rm -f *.aux *.log *.out *.toc *.pdf
|
rm -f *.aux *.log *.out *.toc *.pdf brevetkarte-personalized.tex brevetkarte-blanko.tex brevetkarte-rueckseite.tex $(PDF_FILE_DUPLEX) $(PDF_FILE_BLANKO_DUPLEX)
|
||||||
|
|
||||||
# Clean everything including Docker image
|
# Clean everything including Docker image
|
||||||
clean-all: clean
|
clean-all: clean
|
||||||
@@ -89,19 +120,21 @@ clean-all: clean
|
|||||||
docker rmi $(IMAGE_NAME) 2>/dev/null || true
|
docker rmi $(IMAGE_NAME) 2>/dev/null || true
|
||||||
|
|
||||||
# Rebuild from scratch
|
# Rebuild from scratch
|
||||||
rebuild: clean-all build
|
rebuild: clean-all build-personalized
|
||||||
|
|
||||||
# Show help
|
# Show help
|
||||||
help:
|
help:
|
||||||
@echo "Brevet Card PDF Builder"
|
@echo "Brevet Card PDF Builder"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Available targets:"
|
@echo "Available targets:"
|
||||||
@echo " make build - Build Docker image and compile static front side (default)"
|
@echo " make - Generate and compile front + back side PDFs (default)"
|
||||||
@echo " make build-image - Build Docker image only"
|
@echo " make build-image - Build Docker image only"
|
||||||
@echo " make build-front - Compile static demo front side PDF"
|
|
||||||
@echo " make generate - Generate tex files from CSV + event.yml"
|
@echo " make generate - Generate tex files from CSV + event.yml"
|
||||||
@echo " make build-personalized - Generate and compile front + back side PDFs"
|
@echo " make build-personalized - Generate and compile front + back side PDFs"
|
||||||
@echo " make build-back - Compile back side PDF (after generate)"
|
@echo " make build-blanko - Generate and compile blank card (no CSV needed)"
|
||||||
|
@echo " make build-duplex - Build duplex PDF (front+back interleaved)"
|
||||||
|
@echo " make build-blanko-duplex - Build blank duplex PDF"
|
||||||
|
@echo " make build-back - Compile back side PDF only (after generate)"
|
||||||
@echo " make shell - Open interactive shell in container"
|
@echo " make shell - Open interactive shell in container"
|
||||||
@echo " make clean - Remove generated files (aux, log, pdf)"
|
@echo " make clean - Remove generated files (aux, log, pdf)"
|
||||||
@echo " make clean-all - Remove all files and Docker image"
|
@echo " make clean-all - Remove all files and Docker image"
|
||||||
|
|||||||
@@ -6,14 +6,13 @@ LaTeX-basierter Generator für Audax Randonneurs Allemagne Brevetkarten mit Vord
|
|||||||
|
|
||||||
- Docker
|
- Docker
|
||||||
- Make
|
- Make
|
||||||
- Python 3 + PyYAML (`pip install pyyaml`)
|
|
||||||
|
|
||||||
## Konfigurationsdateien
|
## Konfigurationsdateien
|
||||||
|
|
||||||
Vor dem ersten Build zwei Dateien aus den Beispielen anlegen und befüllen:
|
Vor dem ersten Build zwei Dateien aus den Beispielen anlegen und befüllen:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp "Export Brevetkarte.csv.example" "Export Brevetkarte.csv"
|
cp export_brevetcard.csv.example export_brevetcard.csv
|
||||||
cp event.yml.example event.yml
|
cp event.yml.example event.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -52,7 +51,7 @@ Teilnehmerdaten im Format:
|
|||||||
Startnr, Nachname, Vorname, Straße, PLZ, Ort, Land, Medaille
|
Startnr, Nachname, Vorname, Straße, PLZ, Ort, Land, Medaille
|
||||||
```
|
```
|
||||||
|
|
||||||
Siehe `Export Brevetkarte.csv.example` für das vollständige Format.
|
Siehe `export_brevetcard.csv.example` für das vollständige Format.
|
||||||
|
|
||||||
## Verwendung
|
## Verwendung
|
||||||
|
|
||||||
@@ -68,6 +67,25 @@ Führt folgende Schritte aus:
|
|||||||
3. Erzeugt `brevetkarte-rueckseite.tex` (Rückseite mit Kontrollpunkten aus event.yml)
|
3. Erzeugt `brevetkarte-rueckseite.tex` (Rückseite mit Kontrollpunkten aus event.yml)
|
||||||
4. Kompiliert beide .tex-Dateien zu PDFs
|
4. Kompiliert beide .tex-Dateien zu PDFs
|
||||||
|
|
||||||
|
### Duplex-PDF erzeugen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make build-duplex # personalisierte Karten
|
||||||
|
make build-blanko-duplex # Blanko-Karten
|
||||||
|
```
|
||||||
|
|
||||||
|
Erzeugt ein einzelnes PDF mit abwechselnden Vorder- und Rückseiten für den direkten Duplexdruck: Seite 1 Vorderseite, Seite 2 Rückseite, Seite 3 nächste Vorderseite, usw. Erfordert kein manuelles Zusammenführen zweier Dateien.
|
||||||
|
|
||||||
|
### Blanko-Karten erzeugen und bauen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make build-blanko
|
||||||
|
```
|
||||||
|
|
||||||
|
Erzeugt Blanko-Karten ohne Teilnehmerdaten — keine `export_brevetcard.csv` erforderlich. Sinnvoll für Nachmeldungen oder als Reservekarten vor Ort. Die Veranstaltungsdaten aus `event.yml` werden übernommen, die Teilnehmerfelder bleiben leer.
|
||||||
|
|
||||||
|
Ausgabe: `brevetkarte-blanko.pdf` (Vorderseite) + `brevetkarte-rueckseite.pdf` (Rückseite)
|
||||||
|
|
||||||
### Einzelne Schritte
|
### Einzelne Schritte
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -76,9 +94,6 @@ make generate
|
|||||||
|
|
||||||
# Nur Rückseite kompilieren (nach generate)
|
# Nur Rückseite kompilieren (nach generate)
|
||||||
make build-back
|
make build-back
|
||||||
|
|
||||||
# Statische Demo-Vorderseite bauen (ohne CSV, für Tests)
|
|
||||||
make build-front
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Weitere Befehle
|
### Weitere Befehle
|
||||||
@@ -96,11 +111,10 @@ make help # Alle Befehle anzeigen
|
|||||||
| Datei | Beschreibung |
|
| Datei | Beschreibung |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `event.yml.example` | Vorlage für Veranstaltungsdaten (→ als `event.yml` kopieren) |
|
| `event.yml.example` | Vorlage für Veranstaltungsdaten (→ als `event.yml` kopieren) |
|
||||||
| `Export Brevetkarte.csv.example` | Vorlage für Teilnehmerdaten (→ als `Export Brevetkarte.csv` kopieren) |
|
| `export_brevetcard.csv.example` | Vorlage für Teilnehmerdaten (→ als `export_brevetcard.csv` kopieren) |
|
||||||
| `brevetkarte-template.tex` | Vorlage Vorderseite (Platzhalter aus CSV + event.yml) |
|
| `brevetkarte-template.tex` | Vorlage Vorderseite (Platzhalter aus CSV + event.yml) |
|
||||||
| `brevetkarte-rueckseite-template.tex` | Vorlage Rückseite (Zellplatzhalter aus event.yml) |
|
| `brevetkarte-rueckseite-template.tex` | Vorlage Rückseite (Zellplatzhalter aus event.yml) |
|
||||||
| `brevetkarte.tex` | Statische Demo-Vorderseite (ohne Personalisierung) |
|
| `generate_cards.py` | Generiert .tex-Dateien aus Templates + Konfiguration |
|
||||||
| `generate_cards.py` | Generiert personalisierte .tex-Dateien |
|
|
||||||
| `cyclist-logo.png` | Audax Randonneurs Logo |
|
| `cyclist-logo.png` | Audax Randonneurs Logo |
|
||||||
| `Dockerfile` | Docker-Image-Definition (debian:bookworm-slim + TeX Live) |
|
| `Dockerfile` | Docker-Image-Definition (debian:bookworm-slim + TeX Live) |
|
||||||
| `Makefile` | Build-Automatisierung |
|
| `Makefile` | Build-Automatisierung |
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
\documentclass[a4paper,10pt,landscape]{article}
|
\documentclass[a4paper,10pt,landscape]{article}
|
||||||
\usepackage[utf8]{inputenc}
|
\usepackage[utf8]{inputenc}
|
||||||
\usepackage[T1]{fontenc}
|
\usepackage[T1]{fontenc}
|
||||||
\usepackage[landscape,top=0.8cm,bottom=0.8cm,left=0.8cm,right=0.8cm]{geometry}
|
\usepackage[landscape,top=0.6cm,bottom=0.6cm,left=0.6cm,right=0.6cm]{geometry}
|
||||||
\usepackage{array}
|
\usepackage{array}
|
||||||
\usepackage{helvet}
|
\usepackage{helvet}
|
||||||
|
|
||||||
@@ -12,107 +12,107 @@
|
|||||||
\setlength{\tabcolsep}{3pt}
|
\setlength{\tabcolsep}{3pt}
|
||||||
\pagestyle{empty}
|
\pagestyle{empty}
|
||||||
|
|
||||||
\newcommand{\rowheight}{2.833cm}
|
\newcommand{\rowheight}{3.167cm}
|
||||||
|
|
||||||
\begin{document}
|
\begin{document}
|
||||||
|
|
||||||
% Upper card table (rows 1-3)
|
% Upper card table (rows 1-3)
|
||||||
\noindent
|
\noindent
|
||||||
\begin{tabular}{|p{6.6cm}|p{6.6cm}|p{6.6cm}|p{6.6cm}|}
|
\begin{tabular}{|p{6.9cm}|p{6.9cm}|p{6.9cm}|p{6.9cm}|}
|
||||||
\hline
|
\hline
|
||||||
% Row 1
|
% Row 1
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_1_1}}}
|
{{CELL_1_1}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_1_2}}}
|
{{CELL_1_2}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_1_3}}}
|
{{CELL_1_3}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_1_4}}}
|
{{CELL_1_4}}}
|
||||||
\\
|
\\
|
||||||
\hline
|
\hline
|
||||||
|
|
||||||
% Row 2
|
% Row 2
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_2_1}}}
|
{{CELL_2_1}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_2_2}}}
|
{{CELL_2_2}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_2_3}}}
|
{{CELL_2_3}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_2_4}}}
|
{{CELL_2_4}}}
|
||||||
\\
|
\\
|
||||||
\hline
|
\hline
|
||||||
|
|
||||||
% Row 3
|
% Row 3
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_3_1}}}
|
{{CELL_3_1}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_3_2}}}
|
{{CELL_3_2}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_3_3}}}
|
{{CELL_3_3}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_3_4}}}
|
{{CELL_3_4}}}
|
||||||
\\
|
\\
|
||||||
\hline
|
\hline
|
||||||
\end{tabular}
|
\end{tabular}
|
||||||
|
|
||||||
\vspace{1.8cm}
|
\vspace{0.6cm}
|
||||||
|
|
||||||
% Lower card table (rows 1-3, identical)
|
% Lower card table (rows 1-3, identical)
|
||||||
\noindent
|
\noindent
|
||||||
\begin{tabular}{|p{6.6cm}|p{6.6cm}|p{6.6cm}|p{6.6cm}|}
|
\begin{tabular}{|p{6.9cm}|p{6.9cm}|p{6.9cm}|p{6.9cm}|}
|
||||||
\hline
|
\hline
|
||||||
% Row 1
|
% Row 1
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_1_1}}}
|
{{CELL_1_1}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_1_2}}}
|
{{CELL_1_2}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_1_3}}}
|
{{CELL_1_3}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_1_4}}}
|
{{CELL_1_4}}}
|
||||||
\\
|
\\
|
||||||
\hline
|
\hline
|
||||||
|
|
||||||
% Row 2
|
% Row 2
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_2_1}}}
|
{{CELL_2_1}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_2_2}}}
|
{{CELL_2_2}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_2_3}}}
|
{{CELL_2_3}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_2_4}}}
|
{{CELL_2_4}}}
|
||||||
\\
|
\\
|
||||||
\hline
|
\hline
|
||||||
|
|
||||||
% Row 3
|
% Row 3
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_3_1}}}
|
{{CELL_3_1}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_3_2}}}
|
{{CELL_3_2}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_3_3}}}
|
{{CELL_3_3}}}
|
||||||
&
|
&
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
\parbox[c][\rowheight][t]{6.8cm}{%
|
||||||
{{CELL_3_4}}}
|
{{CELL_3_4}}}
|
||||||
\\
|
\\
|
||||||
\hline
|
\hline
|
||||||
|
|||||||
@@ -1,185 +0,0 @@
|
|||||||
\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}
|
|
||||||
|
|
||||||
\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
|
|
||||||
\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][t]{6.5cm}{%
|
|
||||||
}
|
|
||||||
&
|
|
||||||
\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
|
|
||||||
\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][t]{6.5cm}{%
|
|
||||||
}
|
|
||||||
&
|
|
||||||
\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][t]{6.5cm}{%
|
|
||||||
}
|
|
||||||
\\
|
|
||||||
\hline
|
|
||||||
|
|
||||||
% Row 3
|
|
||||||
\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][t]{6.5cm}{%
|
|
||||||
}
|
|
||||||
&
|
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
|
||||||
}
|
|
||||||
&
|
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
|
||||||
}
|
|
||||||
\\
|
|
||||||
\hline
|
|
||||||
\end{tabular}
|
|
||||||
|
|
||||||
\vspace{1.8cm}
|
|
||||||
|
|
||||||
% Lower card table (rows 1-3, identical)
|
|
||||||
\noindent
|
|
||||||
\begin{tabular}{|p{6.6cm}|p{6.6cm}|p{6.6cm}|p{6.6cm}|}
|
|
||||||
\hline
|
|
||||||
% Row 1
|
|
||||||
\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][t]{6.5cm}{%
|
|
||||||
}
|
|
||||||
&
|
|
||||||
\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
|
|
||||||
\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][t]{6.5cm}{%
|
|
||||||
}
|
|
||||||
&
|
|
||||||
\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][t]{6.5cm}{%
|
|
||||||
}
|
|
||||||
\\
|
|
||||||
\hline
|
|
||||||
|
|
||||||
% Row 3
|
|
||||||
\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][t]{6.5cm}{%
|
|
||||||
}
|
|
||||||
&
|
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
|
||||||
}
|
|
||||||
&
|
|
||||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
|
||||||
}
|
|
||||||
\\
|
|
||||||
\hline
|
|
||||||
\end{tabular}
|
|
||||||
|
|
||||||
\end{document}
|
|
||||||
+23
-23
@@ -1,7 +1,7 @@
|
|||||||
\documentclass[a4paper,10pt,landscape]{article}
|
\documentclass[a4paper,10pt,landscape]{article}
|
||||||
\usepackage[utf8]{inputenc}
|
\usepackage[utf8]{inputenc}
|
||||||
\usepackage[T1]{fontenc}
|
\usepackage[T1]{fontenc}
|
||||||
\usepackage[landscape,top=0.8cm,bottom=0.8cm,left=0.8cm,right=0.8cm]{geometry}
|
\usepackage[landscape,top=0.6cm,bottom=0.6cm,left=0.6cm,right=0.6cm]{geometry}
|
||||||
\usepackage{graphicx}
|
\usepackage{graphicx}
|
||||||
\usepackage{xcolor}
|
\usepackage{xcolor}
|
||||||
\usepackage{tikz}
|
\usepackage{tikz}
|
||||||
@@ -29,34 +29,34 @@
|
|||||||
|
|
||||||
% Brevet card for {{NAME}} (Start #{{STARTNR}})
|
% Brevet card for {{NAME}} (Start #{{STARTNR}})
|
||||||
\noindent
|
\noindent
|
||||||
\begin{tikzpicture}[x=1cm,y=1cm]
|
\begin{tikzpicture}[x=0.990cm,y=1cm]
|
||||||
|
|
||||||
% Black vertical separator lines (drawn first, extend through headers)
|
% 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] (7.2,-8.2) -- (7.2,1.3);
|
||||||
\draw[black,line width=0.5pt] (13.8,-7.2) -- (13.8,1.3);
|
\draw[black,line width=0.5pt] (14.4,-8.2) -- (14.4,1.3);
|
||||||
\draw[black,line width=0.5pt] (20.7,-7.2) -- (20.7,1.3);
|
\draw[black,line width=0.5pt] (21.6,-8.2) -- (21.6,1.3);
|
||||||
|
|
||||||
% Black header boxes (drawn on top)
|
% Black header boxes (drawn on top)
|
||||||
\fill[headerblack] (0,0) rectangle (6.9,1.3);
|
\fill[headerblack] (0,0) rectangle (7.2,1.3);
|
||||||
\node[white,align=center,font=\tiny,text width=6.6cm] at (3.45,0.65) {
|
\node[white,align=center,font=\tiny,text width=6.9cm] at (3.6,0.65) {
|
||||||
Jeder Teilnehmer muss diese Brevetkarte zu jeder Zeit\\
|
Jeder Teilnehmer muss diese Brevetkarte zu jeder Zeit\\
|
||||||
mit sich führen und an den Kontrollen abstempeln lassen\\
|
mit sich führen und an den Kontrollen abstempeln lassen\\
|
||||||
bzw. Fotos erstellen.\\
|
bzw. Fotos erstellen.\\
|
||||||
\textbf{Ohne Kontrollzeiten und Zielzeit keine Wertung!}
|
\textbf{Ohne Kontrollzeiten und Zielzeit keine Wertung!}
|
||||||
};
|
};
|
||||||
|
|
||||||
\fill[headerblack] (6.9,0) rectangle (13.8,1.3);
|
\fill[headerblack] (7.2,0) rectangle (14.4,1.3);
|
||||||
\node[white,font=\Large] at (10.35,0.65) {HOMOLOGATION};
|
\node[white,font=\Large] at (10.8,0.65) {HOMOLOGATION};
|
||||||
|
|
||||||
\fill[headerblack] (13.8,0) rectangle (20.7,1.3);
|
\fill[headerblack] (14.4,0) rectangle (21.6,1.3);
|
||||||
\node[white,font=\Large] at (17.25,0.65) {TEILNEHMER/-IN};
|
\node[white,font=\Large] at (18.0,0.65) {TEILNEHMER/-IN};
|
||||||
|
|
||||||
\fill[headerblack] (20.7,0) rectangle (27.6,1.3);
|
\fill[headerblack] (21.6,0) rectangle (28.8,1.3);
|
||||||
\node[white,align=center,font=\normalsize] at (24.15,0.75) {BREVET DES RANDONNEURS};
|
\node[white,align=center,font=\normalsize] at (25.2,0.75) {BREVET DES RANDONNEURS};
|
||||||
\node[white,font=\Large] at (24.15,0.35) {MONDIAUX};
|
\node[white,font=\Large] at (25.2,0.35) {MONDIAUX};
|
||||||
|
|
||||||
% Column 1 - Rules (left section)
|
% Column 1 - Rules (left section)
|
||||||
\node[anchor=north west,text width=6.6cm,font=\small,align=left] at (0.2,-0.3) {
|
\node[anchor=north west,text width=6.9cm,font=\small,align=left] at (0.2,-0.3) {
|
||||||
\textbf{Es gelten die Regeln von}\\
|
\textbf{Es gelten die Regeln von}\\
|
||||||
\textbf{Randonneur Mondiaux}\\
|
\textbf{Randonneur Mondiaux}\\
|
||||||
\textbf{insbesondere:}
|
\textbf{insbesondere:}
|
||||||
@@ -73,28 +73,28 @@
|
|||||||
\hspace{0.3cm}$\Rightarrow$ \textbf{\underline{Bei Verstoß keine Wertung!}}\\[0.3cm]
|
\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) {
|
\node[anchor=south west,text width=6.9cm,font=\small,align=left] at (0.2,-8.0) {
|
||||||
\textbf{AUDAX RANDONNEURS ALLEMAGNE E.V.}\\
|
\textbf{AUDAX RANDONNEURS ALLEMAGNE E.V.}\\
|
||||||
\href{http://www.audax-randonneure.de}{www.audax-randonneure.de}\\
|
\href{http://www.audax-randonneure.de}{www.audax-randonneure.de}\\
|
||||||
- gegründet 1992 in Hamburg -
|
- gegründet 1992 in Hamburg -
|
||||||
};
|
};
|
||||||
|
|
||||||
% Column 2 - Homologation (middle-left section)
|
% Column 2 - Homologation (middle-left section)
|
||||||
\node[anchor=north,text width=6.6cm,font=\small,align=center] at (10.35,-0.5) {
|
\node[anchor=north,text width=6.9cm,font=\small,align=center] at (10.8,-0.5) {
|
||||||
Der Randonnée wurde beendet in:\\[0.6cm]
|
Der Randonnée wurde beendet in:\\[0.6cm]
|
||||||
\makebox[2cm]{\dotfill}h\makebox[2cm]{\dotfill}min
|
\makebox[2cm]{\dotfill}h\makebox[2cm]{\dotfill}min
|
||||||
};
|
};
|
||||||
|
|
||||||
\node[anchor=center,font=\Large] at (10.35,-4.0) {
|
\node[anchor=center,font=\Large] at (10.8,-4.0) {
|
||||||
HOMOLOGATION
|
HOMOLOGATION
|
||||||
};
|
};
|
||||||
|
|
||||||
\node[anchor=south,text width=6.6cm,font=\small,align=center] at (10.35,-6.8) {
|
\node[anchor=south,text width=6.9cm,font=\small,align=center] at (10.8,-7.8) {
|
||||||
Brevet N° \makebox[5cm]{\dotfill}
|
Brevet N° \makebox[5cm]{\dotfill}
|
||||||
};
|
};
|
||||||
|
|
||||||
% Column 3 - Participant Info (middle-right section)
|
% Column 3 - Participant Info (middle-right section)
|
||||||
\node[anchor=north west,text width=6.6cm,font=\small,align=left] at (14.0,-0.5) {
|
\node[anchor=north west,text width=6.9cm,font=\small,align=left] at (14.6,-0.5) {
|
||||||
Name: {{NAME}}\\[0.4cm]
|
Name: {{NAME}}\\[0.4cm]
|
||||||
Straße: {{STREET}}\\[0.4cm]
|
Straße: {{STREET}}\\[0.4cm]
|
||||||
PLZ/Ort: {{PLZ_ORT}}\\[0.4cm]
|
PLZ/Ort: {{PLZ_ORT}}\\[0.4cm]
|
||||||
@@ -104,11 +104,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
% Column 4 - Event Info (right section)
|
% Column 4 - Event Info (right section)
|
||||||
\node[anchor=north,text width=6.6cm,align=center] at (24.15,-0.4) {
|
\node[anchor=north,text width=6.9cm,align=center] at (25.2,-0.4) {
|
||||||
\includegraphics[width=5.5cm]{cyclist-logo.png}
|
\includegraphics[width=5.5cm]{cyclist-logo.png}
|
||||||
};
|
};
|
||||||
|
|
||||||
\node[anchor=north,text width=6.6cm,font=\small,align=center] at (24.15,-2.2) {
|
\node[anchor=north,text width=6.9cm,font=\small,align=center] at (25.2,-2.2) {
|
||||||
\textbf{{{EVENT_TITLE}}}\\
|
\textbf{{{EVENT_TITLE}}}\\
|
||||||
Randonnée über \textbf{{{EVENT_KM}}} km\\
|
Randonnée über \textbf{{{EVENT_KM}}} km\\
|
||||||
am \textbf{{{EVENT_DATE}}}\\
|
am \textbf{{{EVENT_DATE}}}\\
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
N° ACP du Club \textbf{{{EVENT_CLUB_NR}}}
|
N° ACP du Club \textbf{{{EVENT_CLUB_NR}}}
|
||||||
};
|
};
|
||||||
|
|
||||||
\node[anchor=south,text width=6.6cm,font=\scriptsize,align=center] at (24.15,-7.0) {
|
\node[anchor=south,text width=6.9cm,font=\scriptsize,align=center] at (25.2,-8.0) {
|
||||||
CONTRÔLÉE ET HOMOLOGUÉE EXCLUSIVEMENT PAR\\
|
CONTRÔLÉE ET HOMOLOGUÉE EXCLUSIVEMENT PAR\\
|
||||||
\href{http://www.audax-club-parisien.com}{www.audax-club-parisien.com}\\
|
\href{http://www.audax-club-parisien.com}{www.audax-club-parisien.com}\\
|
||||||
- Société fondée en 1904 -
|
- Société fondée en 1904 -
|
||||||
|
|||||||
-139
@@ -1,139 +0,0 @@
|
|||||||
\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}
|
|
||||||
|
|
||||||
% 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:}
|
|
||||||
{\setlength{\leftmargini}{0.4cm}%
|
|
||||||
\begin{itemize}%
|
|
||||||
\setlength{\itemsep}{1pt}\setlength{\topsep}{2pt}\setlength{\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}
|
|
||||||
+55
-8
@@ -2,6 +2,7 @@
|
|||||||
"""
|
"""
|
||||||
Generate personalized brevet cards from CSV and event config.
|
Generate personalized brevet cards from CSV and event config.
|
||||||
"""
|
"""
|
||||||
|
import argparse
|
||||||
import csv
|
import csv
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -58,7 +59,7 @@ def apply_event_placeholders(text, config):
|
|||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
def generate_backside(template, config):
|
def generate_backside(template, config, num_pages=1):
|
||||||
"""Fill back side template with cell content from event config."""
|
"""Fill back side template with cell content from event config."""
|
||||||
cells = config.get('backside', {})
|
cells = config.get('backside', {})
|
||||||
result = template
|
result = template
|
||||||
@@ -70,7 +71,18 @@ def generate_backside(template, config):
|
|||||||
if content is None:
|
if content is None:
|
||||||
content = ""
|
content = ""
|
||||||
result = result.replace(placeholder, content.strip())
|
result = result.replace(placeholder, content.strip())
|
||||||
return result
|
|
||||||
|
if num_pages <= 1:
|
||||||
|
return result
|
||||||
|
|
||||||
|
# Repeat body between \begin{document} and \end{document} num_pages times
|
||||||
|
begin_marker = '\\begin{document}\n'
|
||||||
|
end_marker = '\\end{document}'
|
||||||
|
begin_idx = result.find(begin_marker) + len(begin_marker)
|
||||||
|
end_idx = result.rfind(end_marker)
|
||||||
|
preamble = result[:begin_idx]
|
||||||
|
body = result[begin_idx:end_idx].rstrip()
|
||||||
|
return preamble + ('\n\n\\newpage\n\n').join([body] * num_pages) + '\n' + result[end_idx:]
|
||||||
|
|
||||||
|
|
||||||
def generate_card_from_template(template, data):
|
def generate_card_from_template(template, data):
|
||||||
@@ -92,8 +104,24 @@ def generate_card_from_template(template, data):
|
|||||||
return card
|
return card
|
||||||
|
|
||||||
|
|
||||||
|
def generate_blanko_card(template):
|
||||||
|
"""Generate a blank card with empty participant fields."""
|
||||||
|
card = template.replace('{{NAME}}', '')
|
||||||
|
card = card.replace('{{STREET}}', '')
|
||||||
|
card = card.replace('{{PLZ_ORT}}', '')
|
||||||
|
card = card.replace('{{LAND}}', '')
|
||||||
|
card = card.replace('{{MEDAILLE}}', '')
|
||||||
|
card = card.replace('{{STARTNR}}', '')
|
||||||
|
return card
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
csv_file = Path("Export Brevetkarte.csv")
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--blanko', action='store_true',
|
||||||
|
help='Generate blank card without participant data')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
csv_file = Path("export_brevetcard.csv")
|
||||||
template_file = Path("brevetkarte-template.tex")
|
template_file = Path("brevetkarte-template.tex")
|
||||||
backside_template_file = Path("brevetkarte-rueckseite-template.tex")
|
backside_template_file = Path("brevetkarte-rueckseite-template.tex")
|
||||||
event_config_file = Path("event.yml")
|
event_config_file = Path("event.yml")
|
||||||
@@ -112,6 +140,24 @@ def main():
|
|||||||
template = template_file.read_text(encoding='utf-8')
|
template = template_file.read_text(encoding='utf-8')
|
||||||
template = apply_event_placeholders(template, event_config)
|
template = apply_event_placeholders(template, event_config)
|
||||||
|
|
||||||
|
# Split preamble from body so \begin{document} appears only once per file
|
||||||
|
marker = '\\begin{document}'
|
||||||
|
doc_idx = template.find(marker)
|
||||||
|
preamble = template[:doc_idx + len(marker)]
|
||||||
|
body = template[doc_idx + len(marker):]
|
||||||
|
|
||||||
|
if args.blanko:
|
||||||
|
blanko_output_file = Path("brevetkarte-blanko.tex")
|
||||||
|
blanko_body = generate_blanko_card(body)
|
||||||
|
blanko_output = preamble + blanko_body + "\n\\vspace{0.6cm}\n\n" + blanko_body + "\n\\end{document}\n"
|
||||||
|
blanko_output_file.write_text(blanko_output, encoding='utf-8')
|
||||||
|
print(f"Generated {blanko_output_file}")
|
||||||
|
backside_template = backside_template_file.read_text(encoding='utf-8')
|
||||||
|
backside_output = generate_backside(backside_template, event_config, num_pages=1)
|
||||||
|
backside_output_file.write_text(backside_output, encoding='utf-8')
|
||||||
|
print(f"Generated {backside_output_file}")
|
||||||
|
return
|
||||||
|
|
||||||
print(f"Reading participant data from {csv_file}...")
|
print(f"Reading participant data from {csv_file}...")
|
||||||
participants = []
|
participants = []
|
||||||
with open(csv_file, 'r', encoding='utf-8-sig') as f:
|
with open(csv_file, 'r', encoding='utf-8-sig') as f:
|
||||||
@@ -129,14 +175,14 @@ def main():
|
|||||||
# Generate personalized front side
|
# Generate personalized front side
|
||||||
cards = []
|
cards = []
|
||||||
for participant in participants:
|
for participant in participants:
|
||||||
card = generate_card_from_template(template, participant)
|
card = generate_card_from_template(body, participant)
|
||||||
cards.append(card)
|
cards.append(card)
|
||||||
|
|
||||||
document_parts = []
|
document_parts = [preamble]
|
||||||
for i, card in enumerate(cards):
|
for i, card in enumerate(cards):
|
||||||
document_parts.append(card)
|
document_parts.append(card)
|
||||||
if i % 2 == 0 and i < len(cards) - 1:
|
if i % 2 == 0 and i < len(cards) - 1:
|
||||||
document_parts.append("\n\\vspace{0.8cm}\n\n")
|
document_parts.append("\n\\vspace{0.6cm}\n\n")
|
||||||
if i % 2 == 1 and i < len(cards) - 1:
|
if i % 2 == 1 and i < len(cards) - 1:
|
||||||
document_parts.append("\n\\newpage\n\n")
|
document_parts.append("\n\\newpage\n\n")
|
||||||
|
|
||||||
@@ -144,10 +190,11 @@ def main():
|
|||||||
output_file.write_text(''.join(document_parts), encoding='utf-8')
|
output_file.write_text(''.join(document_parts), encoding='utf-8')
|
||||||
print(f"Generated {output_file}")
|
print(f"Generated {output_file}")
|
||||||
|
|
||||||
# Generate personalized back side
|
# Generate personalized back side (one page per front page for duplex)
|
||||||
|
num_pages = (len(participants) + 1) // 2
|
||||||
print(f"Reading back side template from {backside_template_file}...")
|
print(f"Reading back side template from {backside_template_file}...")
|
||||||
backside_template = backside_template_file.read_text(encoding='utf-8')
|
backside_template = backside_template_file.read_text(encoding='utf-8')
|
||||||
backside_output = generate_backside(backside_template, event_config)
|
backside_output = generate_backside(backside_template, event_config, num_pages=num_pages)
|
||||||
backside_output_file.write_text(backside_output, encoding='utf-8')
|
backside_output_file.write_text(backside_output, encoding='utf-8')
|
||||||
print(f"Generated {backside_output_file}")
|
print(f"Generated {backside_output_file}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user