Skip to content

Commit f670e20

Browse files
committed
Add activity examples and algorithm documentation
1 parent b608fea commit f670e20

File tree

4 files changed

+133
-0
lines changed

4 files changed

+133
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ stop
130130
## 🗺️ Roadmap
131131

132132
- [x] Support for activity diagrams
133+
- [ ] Support for usecase diagrams
133134
- [ ] Support for sequence diagrams
134135
- [ ] Support for class diagrams
135136
- [ ] Support for component diagrams
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
@startuml
2+
!include https://raw.githubusercontent.com/doubleSlashde/umltheme/main/puml-theme-doubleslash-activity.puml
3+
4+
title Search Flow
5+
6+
Start
7+
8+
if (User is logged in?) then (yes)
9+
:Capture user ID (optional);
10+
else (no)
11+
:Proceed anonymously;
12+
endif
13+
14+
:Enter search query;
15+
:API Call;
16+
:Tokenization, Synonym Handling, etc.;
17+
18+
fork
19+
:Search by description;
20+
fork again
21+
:Search by name;
22+
fork again
23+
:Process by article number;
24+
end fork
25+
:Send search request to OpenSearch;
26+
:Retrieve matching product data;
27+
:Return search results;
28+
:Sorting;
29+
:Ranking;
30+
:Return best match;
31+
:Display search results;
32+
stop
33+
@enduml
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Algorithmus zur Positionierung von Elementen in einem Aktivitätsdiagramm
2+
3+
Der Algorithmus positioniert Knoten eines Aktivitätsdiagramms rekursiv, wobei folgende Knotentypen behandelt werden:
4+
5+
- **Start- und Endknoten**
6+
- **Aktivitätsknoten** (immer einen Eingang, genau einen Ausgang)
7+
- **Bedingungsknoten** (zwei Ausgänge: „wahr" und „falsch")
8+
- **Merge-Knoten** (zwei Eingänge)
9+
10+
Alle Knoten werden vertikal in gleichen Abständen angeordnet (von oben nach unten). Zusätzlich wird bei Bedingungen der falsche Pfad um einen festen horizontalen Offset verschoben. Wichtig ist, dass auch bei Bedingungen, die auf bereits verschobenen (falschen) Pfaden auftreten, der zusätzliche Offset kumulativ angewendet wird – und dass alle nachfolgenden Knoten, egal ob auf dem ursprünglich „richtigen" (vertikalen) Pfad oder auf einem falschen Pfad, stets mindestens den maximal erreichten Offset übernehmen.
11+
12+
---
13+
14+
### Parameter
15+
16+
- **verticalSpacing:** Fester vertikaler Abstand zwischen den Knoten.
17+
- **horizontalOffset:** Fester horizontaler Versatz, der bei jedem Übergang in den falschen Pfad addiert wird.
18+
- **currentOffset:** Lokaler Offset, der den kumulierten Versatz entlang des aktuellen Pfades angibt.
19+
- **globalOffset:** Der bislang maximale Offset, der in falschen Pfaden gesetzt wurde und auch auf den „richtigen" (vertikalen) Pfad übernommen wird, um bereits verankerte falsche Pfade nicht zu "verrutschen".
20+
21+
---
22+
23+
### Pseudocode
24+
25+
```pseudo
26+
function layout(node, baseX, currentY, currentOffset, globalOffset):
27+
// Positioniere den aktuellen Knoten:
28+
// Der x-Wert entspricht dem Basiswert plus dem maximalen Offset (currentOffset oder globalOffset)
29+
node.x = baseX + max(currentOffset, globalOffset)
30+
node.y = currentY
31+
32+
// Bereite den nächsten vertikalen Startpunkt vor
33+
newY = currentY + verticalSpacing
34+
35+
if node.type == 'Bedingung':
36+
// RICHTIGER Pfad: Der True-Ausgang folgt vertikal ohne zusätzlichen Offset.
37+
if node.trueSuccessor exists:
38+
layout(node.trueSuccessor, baseX, newY, currentOffset, globalOffset)
39+
40+
// FALSCHER Pfad: Hier wird der currentOffset um den horizontalOffset erhöht.
41+
newFalseOffset = currentOffset + horizontalOffset
42+
// Aktualisiere globalOffset, sodass er den maximal erreichten Offset abbildet.
43+
newGlobalOffset = max(globalOffset, newFalseOffset)
44+
if node.falseSuccessor exists:
45+
layout(node.falseSuccessor, baseX, newY, newFalseOffset, newGlobalOffset)
46+
47+
else if node.type == 'Aktivität' or node.type == 'Start' or node.type == 'Merge':
48+
// Diese Knoten haben einen einzigen Ausgang.
49+
if node.successor exists:
50+
layout(node.successor, baseX, newY, currentOffset, globalOffset)
51+
52+
else if node.type == 'End':
53+
// Endknoten: Keine Nachfolger
54+
return
55+
```
56+
57+
---
58+
59+
### Funktionsweise und Besonderheiten
60+
61+
1. **Start und Vertikale Platzierung:**
62+
Der Layout-Prozess beginnt mit dem Startknoten. Jeder Knoten wird so positioniert, dass seine x-Koordinate `baseX + max(currentOffset, globalOffset)` ist. Der y-Wert wird stets um den festen `verticalSpacing` erhöht.
63+
64+
2. **Bedingungsknoten:**
65+
- Beim **wahren Ausgang** (True-Pfad) bleibt der `currentOffset` unverändert – der Pfad verläuft vertikal.
66+
- Beim **falschen Ausgang** (False-Pfad) wird der `currentOffset` um `horizontalOffset` erhöht. Dieser neue Offset wird dann als Basis für alle Knoten in diesem Pfad verwendet.
67+
- Gleichzeitig wird der `globalOffset` aktualisiert, sodass auch Knoten, die anschließend auf einem "richtigen" (vertikalen) Pfad folgen, den maximal erreichten Offset übernehmen. Das ist entscheidend, um auch dann, wenn auf dem vertikalen Pfad wieder eine Bedingung auftritt, alle zuvor verschobenen falschen Pfade mitzuschieben.
68+
69+
3. **Konditionen auf falschen Pfaden:**
70+
Der Algorithmus behandelt Bedingungen auf falschen Pfaden genauso wie Bedingungen auf dem vertikalen Pfad. Das bedeutet:
71+
- Auch hier wird beim falschen Ausgang der `currentOffset` um den `horizontalOffset` erhöht und der `globalOffset` angepasst.
72+
- Somit wird sichergestellt, dass sich bei mehrfach verschachtelten Bedingungen die Verschiebung nach rechts stets kumulativ erhöht.
73+
74+
4. **Merge-Knoten:**
75+
Bei Merge-Knoten, die zwei Eingänge besitzen, kann es nötig sein, die x-Position anhand der x-Werte beider Eingänge zu berechnen (beispielsweise den maximalen Wert). Im obigen Pseudocode wird angenommen, dass der bereits übergebene Offset ausreichend ist; je nach konkreter Implementierung kann hier noch eine Zusammenführungslogik ergänzt werden.
76+
77+
---
78+
79+
### Beispielaufruf
80+
81+
Der Algorithmus wird mit dem Startknoten initialisiert, z. B.:
82+
83+
```pseudo
84+
layout(startNode, 0, 0, 0, 0)
85+
```
86+
87+
Dabei wird `baseX` als 0 gewählt und sowohl `currentOffset` als auch `globalOffset` starten bei 0.
88+
89+
---
90+
91+
### Zusammenfassung
92+
93+
- **Rekursives Layout:** Jeder Knoten wird unter Berücksichtigung von vertikalem Abstand und horizontalem Offset positioniert.
94+
- **Bedingungen:**
95+
- Der True-Pfad bleibt vertikal, während der False-Pfad um einen festen horizontalen Versatz nach rechts verschoben wird.
96+
- Dieser Versatz wird kumulativ weitergegeben, sodass auch bei Bedingungen auf bereits falschen Pfaden alle nachfolgenden Knoten entsprechend verschoben werden.
97+
- **globalOffset:** Er gewährleistet, dass alle Knoten – auch wenn sie später im vertikalen Pfad auftauchen – mindestens den maximal erreichten Offset übernehmen, um die Konsistenz des Layouts zu sichern.
98+
99+
Diese Beschreibung sollte alle geforderten Layout-Regeln und das Verhalten bei verschachtelten Bedingungen abdecken.

0 commit comments

Comments
 (0)