docs: add comprehensive README, architecture documentation, and file format specification
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
# 🖋️ ink-notes
|
||||
|
||||
Eine latenzoptimierte, hardwarebeschleunigte Inking- und Notizbuch-Anwendung für Linux, entwickelt in **Rust** mit **wgpu** und **winit**.
|
||||
|
||||
`ink-notes` kombiniert minimale Eingabelatenz beim Zeichnen mit Stift, Touchpad oder Maus mit einem flüssigen stufenlosen Viewport, automatischer Geometrie- und Formerkennung, Objekttransformationen, Multi-Dokumenten-Verwaltung und Vektor-PDF-Export.
|
||||
|
||||
---
|
||||
|
||||
## ✨ Features im Überblick
|
||||
|
||||
### ⚡ Latenzoptimierte Inking-Pipeline
|
||||
- **Hardware-Rendering:** Direct-to-Screen-Rendering mit `wgpu` (Vulkan / X11 / Wayland) unter Nutzung von `PresentMode::Mailbox` für minimale Eingabeverzögerung.
|
||||
- **1€-Filter (One-Euro-Filter):** Dynamischer Tiefpassfilter zur Glättung von Zittern bei langsamen Bewegungen ohne spürbare Latenz bei schnellen Schwüngen.
|
||||
- **Centripetal Catmull-Rom Splines:** Weiche C1-stetige Kurveninterpolation ohne Überschwinger oder Schleifen.
|
||||
- **Drucksensitive Dreiecksstreifen-Tessellierung:** Rechnerische Generierung von Triangle-Meshes mit winkelhalbierenden Normalenvektoren entlang des Pfads.
|
||||
- **Werkzeuge:**
|
||||
- **Stift (Pen):** Feine, variable Strichstärken (0.3 mm bis 1.2 mm) mit Notiz-Farben (Schwarz, Blau, Rot, Grün, Grau).
|
||||
- **Textmarker (Highlighter):** Breite, halbtransparente Striche (4.0 mm bis 8.0 mm) mit Multiplikations-Blending.
|
||||
- **Radierer (Eraser):** Segment- und abstandsbasierte Löschung einzelner Striche auf dem DIN-A4-Canvas.
|
||||
|
||||
### 🔍 Stufenloser Zoom & Pan (Kamera)
|
||||
- **Viewport-Transformation:** 2D-Projektionsmatrix im WGSL-Vertex-Shader.
|
||||
- **Cursor-zentrierter Zoom:** Stufenloses Zoomen von **25 % bis 500 %** zentriert auf die Cursor-Position via Mausrad, Trackpad-Pinch oder Tastenkürzel (`Strg +` / `Strg -` / `Strg 0`).
|
||||
- **Pan:** Verschieben des Canvas per mittlerer Maustaste, `Leertaste + Drag` oder Trackpad-Pan.
|
||||
- **Inverse Koordinatentransformation:** Präzise Umrechnung von Bildschirm- in DIN-A4-Dokumentkoordinaten (`screen_to_page`).
|
||||
|
||||
### 📐 Geometrie- & Objekterkennung (Shape Recognition)
|
||||
- **Erkannte Primitiven:**
|
||||
- **Geraden (Line):** Sehnen- zu Pfadlängenverhältnis > 0.92.
|
||||
- **Rechtecke (Rectangle):** 4 orthogonale Ecken via Douglas-Peucker-Polygonzug (RDP).
|
||||
- **Kreise & Ellipsen (Circle/Ellipse):** Geschlossene Pfade mit minimaler Varianz via Least-Squares Circle Fit.
|
||||
- **Koordinatensysteme (Axes):** Zwei orthogonale Achsen (80°–100° gesnappt auf exakt 90°) mit optionalen Richtungspfeilen.
|
||||
- **Dreiecke, Rhomben / Rauten & Oktaeder:** Regelmäßige Polygone mit Eckpunkt-Analyse.
|
||||
- **Interaktionsmodelle:**
|
||||
- **Draw-and-Hold:** Verweilt der Stift am Ende eines Strichs für > 400 ms regungslos (< 3 px), snappt die Skizze sofort automatisch in eine perfekte Vektorform ein.
|
||||
- **Formen-Werkzeug (Shape Mode):** Direkte Erkennung und Ersetzung beim Loslassen.
|
||||
|
||||
### 🖐️ Objektauswahl & Transformation (Lasso / Select)
|
||||
- **Lasso & Klick-Auswahl:** Schnelles Markieren einzelner Striche oder Gruppen per Rahmen (`V`).
|
||||
- **Echtzeit-Verschieben:** Freies Verschieben ausgewählter Objekte über die Seite.
|
||||
- **Stufenlose Skalierung:** Größenänderung über interaktive Eck-Griffe.
|
||||
- **Drehung:** Stufenlose Rotation um das Objektzentrum über den oberen Dreh-Griff oder exakte 90°-Schritte mit Taste `R`.
|
||||
- **Multicolor-Umfärbung:** Ausgewählte Objekte direkt über die Farbpalette umfärben.
|
||||
- **Clipboard & Editieren:** Kopieren (`Strg + C`), Einfügen (`Strg + V`) und Löschen (`Entf` / `Backspace`).
|
||||
- **Undo / Redo:** Vollständige Transaktionshistorie (`Strg + Z` / `Strg + Y`) für alle Aktionen inklusive Transformationen.
|
||||
|
||||
### 📚 Multi-Dokumenten- & Notizbuch-Verwaltung
|
||||
- **Dateisystem-Architektur:** Jedes Dokument wird in einem separaten Verzeichnis unter `~/.local/share/ink-notes/notebooks/<id>/` mit `manifest.json` und Einzelseiten (`page_<id>.json`) gespeichert.
|
||||
- **Dokumenten-Manager:** Dunkles Glassmorphism-Modal direkt in der Toolbar:
|
||||
- Neues Notizbuch anlegen.
|
||||
- Zwischen Notizbüchern mit einem Klick wechseln.
|
||||
- Dokumente direkt umbenennen (`✏`).
|
||||
- Dokumente löschen (`🗑`).
|
||||
- **Verlustfreier Wechsel:** Beim Dokumentenwechsel sichert ein synchroner Disk-Flush alle anstehenden Änderungen garantiert ab.
|
||||
|
||||
### 📄 Seiten & Hintergründe
|
||||
- **Virtuelles DIN-A4-Raster:** 2100 × 2970 Koordinateneinheiten (10 Einheiten = 1 mm).
|
||||
- **Hintergrundmuster:**
|
||||
- Blanko
|
||||
- Kariert (5 mm Raster)
|
||||
- Liniert (7.5 mm Zeilenabstand)
|
||||
- Punktraster (5 mm Dot-Grid)
|
||||
- **Seitenverwaltung:** Vor- und Zurückblättern, neue Seiten anfügen, Seitensprung-Menü.
|
||||
|
||||
### 💾 Autosave & Persistenz
|
||||
- **Asynchroner Autosave-Controller:** Sichert Änderungen im Hintergrund-Thread nach 1.5 s Ruhezeit (Debounce), ohne das Zeichnen zu blockieren.
|
||||
- **Atomares Schreiben:** Temp-Dateien mit atomarem Rename (`manifest.json.tmp` -> `manifest.json`) schützen vor Datenkorruption bei Abstürzen.
|
||||
- **Sicherer Shutdown:** `ESC` oder Schließen des Fensters führt vor Programmende einen vollständigen synchronen Flush aus.
|
||||
|
||||
### 🖨️ Vektor-PDF-Export
|
||||
- Exportiert das gesamte Dokument via `printpdf` nach `./export.pdf`.
|
||||
- Striche und geometrische Formen werden als skalierbare Vektoren ausgegeben.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Schnellstart
|
||||
|
||||
### Voraussetzungen
|
||||
- **Rust & Cargo:** Version 1.75 oder neuer (`rustup update stable`)
|
||||
- **System-Bibliotheken (Linux):**
|
||||
- Vulkan-Treiber (z. B. `mesa-vulkan-drivers` oder proprietäre Treiber)
|
||||
- X11 / XWayland Bibliotheken (`libx11-dev`, `libxcursor-dev`, `libxrandr-dev`, `libxi-dev`, `libxkbcommon-dev`)
|
||||
|
||||
### Bauen & Ausführen
|
||||
|
||||
```bash
|
||||
# Repository klonen
|
||||
git clone gitea@farmersdog.pansi.eu:harald/ink-notes.git
|
||||
cd ink-notes
|
||||
|
||||
# Kompilieren und starten via Starter-Skript
|
||||
./run.sh
|
||||
```
|
||||
|
||||
Alternativ direkt mit Cargo:
|
||||
|
||||
```bash
|
||||
cargo run --release
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⌨️ Tastatur- & Maus-Shortcuts
|
||||
|
||||
| Aktion | Tastenkürzel / Mausgeste |
|
||||
| :--- | :--- |
|
||||
| **Zeichnen** | Linke Maustaste / Stiftspitze |
|
||||
| **Canvas verschieben (Pan)** | Mittlere Maustaste **oder** `Leertaste + Drag` |
|
||||
| **Zoom zentriert auf Cursor** | Mausrad / Touchpad-Pinch |
|
||||
| **Zoom zurücksetzen (100 %)** | `Strg + 0` |
|
||||
| **Zoom In / Out** | `Strg + +` / `Strg + -` |
|
||||
| **Auswahlwerkzeug (Lasso)** | `V` |
|
||||
| **Auswahl um 90° drehen** | `R` |
|
||||
| **Kopieren & Einfügen** | `Strg + C` / `Strg + V` |
|
||||
| **Auswahl löschen** | `Entf` oder `Backspace` |
|
||||
| **Undo / Redo** | `Strg + Z` / `Strg + Y` (oder `Strg + Shift + Z`) |
|
||||
| **Nächste Seite** | `Bild ab (PageDown)` oder `N` |
|
||||
| **Vorherige Seite** | `Bild auf (PageUp)` |
|
||||
| **Erste / Letzte Seite** | `Pos 1 (Home)` / `Ende (End)` |
|
||||
| **PDF-Export** | `Strg + E` oder `Strg + S` |
|
||||
| **Beenden (mit Disk-Flush)** | `Esc` oder `Q` |
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Projekt- und Modul-Architektur
|
||||
|
||||
```text
|
||||
src/
|
||||
├── main.rs # Event-Loop (winit), Input-Routing, App-Orchestrierung
|
||||
├── lib.rs # Bibliotheks-Exporte für Tests und Komponenten
|
||||
├── canvas.rs # wgpu Render-Pipeline, GPU-Buffer, Zeichenzustand
|
||||
├── viewport.rs # Kamera-Pan, Zoom, 2D-Transformationsmatrizen
|
||||
├── shader.wgsl # WGSL Vertex- & Fragment-Shader für Inking-Meshes
|
||||
├── filter.rs # One-Euro-Filter gegen Eingabe-Jitter
|
||||
├── spline.rs # Centripetal Catmull-Rom & Dreiecksstreifen-Tessellierung
|
||||
├── geometry.rs # RDP-Algorithmus, Least-Squares Circle Fit, Shape Recognition
|
||||
├── selection.rs # Lasso-Auswahl, Bounding-Box, Griffe, Rotation & Skalierung
|
||||
├── background.rs # Tessellierung für Kariert, Liniert, Punktraster
|
||||
├── document.rs # Notizbuch-Datenmodell, Seiten, DIN-A4-Koordinatensystem
|
||||
├── history.rs # Undo/Redo-Transaktionsstapel (Add, Erase, Transform)
|
||||
├── storage.rs # Atomares Laden/Speichern von Manifest & Seiten, Multi-Notebooks
|
||||
├── autosave.rs # Debounced Hintergrund-Autosave mit MPSC-Kanal
|
||||
├── export.rs # Skalierbarer Vektor-PDF-Export via printpdf
|
||||
└── ui.rs # Floating Glassmorphism-Toolbar & Dokumenten-Manager (egui)
|
||||
```
|
||||
|
||||
Ausführliche Details zur Architektur und mathematischen Modellen findest du unter [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Tests ausführen
|
||||
|
||||
Die gesamte Inking-Pipeline, Geometrieerkennung und Speicherlogik ist mit Unit-Tests abgesichert:
|
||||
|
||||
```bash
|
||||
cargo test
|
||||
```
|
||||
|
||||
Alle 53 Unit-Tests prüfen Berechnungen, Hit-Testing, Undo/Redo und Persistenz konsistent ab.
|
||||
|
||||
---
|
||||
|
||||
## 📄 Lizenz
|
||||
|
||||
Proprietäres Notiz-Projekt für Linux. Alle Rechte vorbehalten.
|
||||
@@ -0,0 +1,139 @@
|
||||
# Architektur & Technische Dokumentation von ink-notes
|
||||
|
||||
Dieses Dokument beschreibt die interne Architektur, mathematische Modelle und Rendering-Pipelines von `ink-notes`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Die Inking-Pipeline
|
||||
|
||||
```
|
||||
[Hardware Stylus / Touch / Maus]
|
||||
│
|
||||
▼
|
||||
[winit Event-Loop]
|
||||
│ (tx, ty, pressure, timestamp)
|
||||
▼
|
||||
[Viewport Invertierung] (screen_to_page: Umrechnung in DIN-A4-Einheiten)
|
||||
│
|
||||
▼
|
||||
[1€-Filter] (Jitter-Beseitigung bei langsamen Bewegungen)
|
||||
│
|
||||
▼
|
||||
[Centripetal Catmull-Rom] (C1-stetige Spline-Interpolation, alpha = 0.5)
|
||||
│
|
||||
▼
|
||||
[Mesh-Tessellierung] (Drucksensitive Dreiecksstreifen via Normalen)
|
||||
│
|
||||
▼
|
||||
[wgpu GPU-Buffer] (Vertex- & Index-Buffer im VRAM)
|
||||
```
|
||||
|
||||
### 1.1. 1€-Filter (One-Euro-Filter)
|
||||
Stift- und Touch-Eingaben unterliegen bei niedrigen Geschwindigkeiten oft Mikrozittern (Jitter). Standard-Tiefpassfilter verursachen jedoch bei schnellen Schwüngen eine störende Verzögerung (Latenz).
|
||||
|
||||
Der 1€-Filter (`filter.rs`) löst dieses Dilemma mit einer adaptiven Grenzfrequenz $f_c$:
|
||||
$$f_c = f_{c,\min} + \beta \cdot |\dot{x}|$$
|
||||
- Bei geringer Geschwindigkeit ($|\dot{x}| \approx 0$) dominiert $f_{c,\min}$, wodurch Zittern maximal geglättet wird.
|
||||
- Bei schnellen Zügen wächst $\beta \cdot |\dot{x}|$ an, wodurch der Filter durchlässig wird und Latenz eliminiert.
|
||||
|
||||
### 1.2. Centripetal Catmull-Rom Splines
|
||||
Um Ecken zu vermeiden und eine organische Schriftführung zu erzielen, werden Abtastpunkte mit einem zentripetalen Catmull-Rom-Spline (`spline.rs`) interpoliert ($\alpha = 0.5$):
|
||||
$$t_{i+1} = t_i + ||P_{i+1} - P_i||^\alpha$$
|
||||
Diese Parametrisierung garantiert:
|
||||
- Keine Selbstüberschneidungen bei scharfen Wendungen.
|
||||
- Keine unerwünschten Cusp-Schleifen.
|
||||
- Perfekte $C^1$-Stetigkeit an den Stützstellen.
|
||||
|
||||
### 1.3. Drucksensitive Dreiecksstreifen (Tessellierung)
|
||||
Aus den interpolierten Spline-Punkten mit Radius $r_i = f(\text{pressure}_i)$ wird ein Triangle-Strip erzeugt:
|
||||
1. Richtungsvektor $T_i = P_{i+1} - P_i$.
|
||||
2. Senkrechter Normalenvektor $N_i = (-T_{i,y}, T_{i,x}) / ||T_i||$.
|
||||
3. An inneren Stützstellen werden Normalen benachbarter Segmente gemittelt (Winkelhalbierende).
|
||||
4. Eckpunkte des Dreiecksstreifens:
|
||||
$$V_{i,\text{left}} = P_i + N_i \cdot r_i, \quad V_{i,\text{right}} = P_i - N_i \cdot r_i$$
|
||||
|
||||
---
|
||||
|
||||
## 2. Rendering & Kamera-Pipeline (`wgpu`)
|
||||
|
||||
### 2.1. Virtuelles Koordinatensystem
|
||||
Die Anwendung rechnet intern in virtuellen DIN-A4-Koordinaten:
|
||||
- Breite: **2100 Einheiten** (210 mm)
|
||||
- Höhe: **2970 Einheiten** (297 mm)
|
||||
- 1 mm entspricht exakt **10 Einheiten**.
|
||||
|
||||
### 2.2. Viewport & Projektionsmatrix (`viewport.rs`)
|
||||
Der Vertex-Shader transformiert DIN-A4-Koordinaten über eine Orthogonal-Projektion kombiniert mit Pan und Zoom in Normalized Device Coordinates (NDC, $[-1, 1]$):
|
||||
|
||||
```wgsl
|
||||
struct CameraUniform {
|
||||
transform: mat4x4<f32>,
|
||||
};
|
||||
```
|
||||
|
||||
Die Projektionsmatrix $M$ wird berechnet aus:
|
||||
1. Skalierung des DIN-A4-Papiers auf den Viewport unter Berücksichtigung des Seitenverhältnisses.
|
||||
2. Anwenden des Zoom-Faktors $z \in [0.25, 5.0]$.
|
||||
3. Translation durch den Pan-Offset $(p_x, p_y)$.
|
||||
|
||||
### 2.3. Cursor-zentrierter Zoom
|
||||
Beim Zoomen mit dem Mausrad wird der neue Pan-Offset so korrigiert, dass der Punkt unter dem Cursor fixiert bleibt:
|
||||
$$\vec{p}_{\text{neu}} = \vec{c} - (\vec{c} - \vec{p}_{\text{alt}}) \cdot \frac{z_{\text{neu}}}{z_{\text{alt}}}$$
|
||||
|
||||
### 2.4. Render-Passes
|
||||
In jedem Frame werden zwei Hauptpässe durchlaufen:
|
||||
1. **Pass 1 (Canvas):**
|
||||
- Hintergrund-Quad und Linien/Gitter (Instanced oder Batch Vertex-Buffer).
|
||||
- Gespeicherte Striche und Geometrie-Meshes.
|
||||
- Aktiver Live-Strich (Ephemeral Buffer).
|
||||
- Auswahl-Overlay & Transformationsgriffe.
|
||||
2. **Pass 2 (egui UI):**
|
||||
- Floating Glassmorphism-Toolbar.
|
||||
- Farb- und Werkzeug-Popovers.
|
||||
- Modal-Dokumentenmanager.
|
||||
|
||||
---
|
||||
|
||||
## 3. Geometrieerkennung & Shape-Fitting (`geometry.rs`)
|
||||
|
||||
Die Erkennung erfolgt rein analytisch und deterministisch ohne schwere ML-Frameworks:
|
||||
|
||||
### 3.1. Ramer-Douglas-Peucker (RDP)
|
||||
Reduziert den Rohpfad auf signifikante Eckpunkte mit konfigurierbarem Toleranzabstand $\epsilon$.
|
||||
|
||||
### 3.2. Erkennungsregeln:
|
||||
- **Gerade:** Verhältnis von Sehnenlänge ($||P_{\text{end}} - P_{\text{start}}||$) zur Pfad-Bogenlänge $> 0.92$.
|
||||
- **Rechteck:** RDP liefert 4 dominante Ecken; Kantenwinkel liegen zwischen $75^\circ$ und $105^\circ$.
|
||||
- **Kreis / Ellipse:** Pfad ist geschlossen ($||P_{\text{start}} - P_{\text{end}}|| < 0.1 \times \text{Umfang}$); Standardabweichung der Radien vom Mittelpunkt ist minimal ($< 0.12 \times \bar{r}$).
|
||||
- **Koordinatensystem:** Zwei orthogonale Schenkel mit Schnittpunkt nahe dem Start/Ende; Winkel $80^\circ$ bis $100^\circ$ wird exakt auf $90^\circ$ eingerastet; positive Achsenenden erhalten Pfeilspitzen.
|
||||
- **Dreiecke / Rhomben / Oktaeder:** Spezifische Eckpunkt- und Symmetrieanalysen der RDP-Kontur.
|
||||
|
||||
### 3.3. Draw-and-Hold Erkennung
|
||||
Hält der Anwender den Stift am Ende eines Strichs für $> 400\text{ ms}$ innerhalb eines Radius von $< 3\text{ px}$ ruhig, wird die Form im fliegenden Wechsel als Vektorform visualisiert und beim Abheben des Stifts fixiert.
|
||||
|
||||
---
|
||||
|
||||
## 4. Persistenz & Autosave-Architektur (`storage.rs`, `autosave.rs`)
|
||||
|
||||
```
|
||||
[UI / Inking Event]
|
||||
│
|
||||
▼
|
||||
[mark_page_dirty]
|
||||
│
|
||||
▼
|
||||
[AutosaveController] ──(1.5s Debounce)──► [Hintergrund-Thread (MPSC)]
|
||||
│
|
||||
▼
|
||||
[Temp-Datei *.tmp schreiben]
|
||||
│
|
||||
▼
|
||||
[Atomares std::fs::rename]
|
||||
│
|
||||
▼
|
||||
[manifest.json / page_<id>.json]
|
||||
```
|
||||
|
||||
- **Keine UI-Blockierung:** Disk-I/O erfolgt vollständig in einem dedizierten Worker-Thread.
|
||||
- **Atomarität:** Daten werden stets zuerst in `.json.tmp` geschrieben und via `fs::rename` atomar ersetzt.
|
||||
- **Verlustfreier Notizbuchwechsel:** Bei `switch_notebook_dir` wird synchron `flush()` aufgerufen, um alle ungespeicherten Daten des aktuellen Dokuments sicherzustellen, bevor der Pfad gewechselt wird.
|
||||
@@ -0,0 +1,134 @@
|
||||
# Dateiformat & Speicherstruktur von ink-notes
|
||||
|
||||
Dieses Dokument beschreibt die Speicherstruktur und die JSON-Dateiformate, mit denen `ink-notes` Dokumente auf dem Dateisystem ablegt.
|
||||
|
||||
---
|
||||
|
||||
## 1. Verzeichnisstruktur
|
||||
|
||||
Notizbücher werden standardmäßig unter dem XDG-Datenpfad gespeichert:
|
||||
|
||||
```text
|
||||
~/.local/share/ink-notes/
|
||||
└── notebooks/
|
||||
├── <notebook_id_1>/
|
||||
│ ├── manifest.json
|
||||
│ ├── page_1.json
|
||||
│ ├── page_2.json
|
||||
│ └── ...
|
||||
└── <notebook_id_2>/
|
||||
├── manifest.json
|
||||
└── page_1.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Dokumenten-Manifest (`manifest.json`)
|
||||
|
||||
Das Manifest enthält Metadaten über das gesamte Dokument sowie die Reihenfolge und IDs aller Seiten:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "notebook-a1b2c3d4",
|
||||
"title": "Mathematik Vorlesung",
|
||||
"version": 1,
|
||||
"pages": [
|
||||
{
|
||||
"id": 1,
|
||||
"file_name": "page_1.json"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"file_name": "page_2.json"
|
||||
}
|
||||
],
|
||||
"current_page_index": 0,
|
||||
"next_page_id": 3,
|
||||
"next_stroke_id": 42,
|
||||
"created_at": 1775460000,
|
||||
"modified_at": 1775463600
|
||||
}
|
||||
```
|
||||
|
||||
### Felder:
|
||||
- `id`: Eindeutige ID des Notizbuchs (z. B. UUID oder `"default"`).
|
||||
- `title`: Vom Nutzer vergebener Anzeigename des Notizbuchs.
|
||||
- `version`: Format-Versionsnummer (aktuell `1`).
|
||||
- `pages`: Geordnete Liste von Seitenreferenzen.
|
||||
- `current_page_index`: Index der zuletzt aktiven Seite für Session-Restore.
|
||||
- `next_page_id`: Inkrementierender ID-Zähler für neue Seiten.
|
||||
- `next_stroke_id`: Globaler ID-Zähler für neue Striche.
|
||||
- `created_at` / `modified_at`: UNIX-Zeitstempel in Sekunden.
|
||||
|
||||
---
|
||||
|
||||
## 3. Seitendatei (`page_<id>.json`)
|
||||
|
||||
Jede Seite wird in einer eigenen Datei gespeichert, um Lazy-Loading und schnelles inkrementelles Speichern zu ermöglichen.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"background": "Grid5mm",
|
||||
"strokes": [
|
||||
{
|
||||
"id": 1,
|
||||
"color": [0.12, 0.12, 0.14, 1.0],
|
||||
"width_mm": 0.5,
|
||||
"samples": [
|
||||
{
|
||||
"x": 350.2,
|
||||
"y": 420.5,
|
||||
"pressure": 0.65,
|
||||
"timestamp": 12.345
|
||||
},
|
||||
{
|
||||
"x": 352.1,
|
||||
"y": 425.8,
|
||||
"pressure": 0.70,
|
||||
"timestamp": 12.355
|
||||
}
|
||||
],
|
||||
"recognized_shape": null
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"color": [0.15, 0.35, 0.85, 1.0],
|
||||
"width_mm": 0.8,
|
||||
"samples": [],
|
||||
"recognized_shape": {
|
||||
"Rectangle": {
|
||||
"top_left": { "x": 500.0, "y": 600.0 },
|
||||
"width": 300.0,
|
||||
"height": 200.0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Felder:
|
||||
- `id`: Eindeutige ID der Seite.
|
||||
- `background`: Papiermuster (`Blank`, `Grid5mm`, `Lined`, `DotGrid`).
|
||||
- `strokes`: Liste der auf der Seite gezeichneten Striche und Vektorformen.
|
||||
- `id`: Eindeutige ID des Strichs.
|
||||
- `color`: RGBA-Farbwerte im Bereich `[0.0, 1.0]`.
|
||||
- `width_mm`: Basis-Strichbreite in Millimetern.
|
||||
- `samples`: Rohabtastpunkte entlang des Pfads (`x`, `y` in DIN-A4-Einheiten, `pressure` in `[0.0, 1.0]`, `timestamp` in Sekunden).
|
||||
- `recognized_shape`: Optionales Enum für geometrische Vektorformen:
|
||||
- `Line { start, end }`
|
||||
- `Rectangle { top_left, width, height }`
|
||||
- `Circle { center, radius }`
|
||||
- `Axes { origin, x_end, y_end, has_arrows }`
|
||||
- `Triangle { p1, p2, p3 }`
|
||||
- `Rhombus { center, width, height }`
|
||||
- `Octahedron { center, radius }`
|
||||
|
||||
---
|
||||
|
||||
## 4. Atomares Schreibverfahren
|
||||
|
||||
Um Datenverlust bei Stromausfall oder plötzlichem Prozessabbruch zu verhindern:
|
||||
1. Daten werden in `<ziel>.tmp` serialisiert und per `fsync` auf das Speichermedium geschrieben.
|
||||
2. Mittels `std::fs::rename("<ziel>.tmp", "<ziel>")` wird die Zieldatei auf POSIX-Systemen atomar ersetzt.
|
||||
Reference in New Issue
Block a user