Beispiel 5 — Zahnrad
Das komplexeste Beispiel: Ein Zahnrad wird durch drei aufeinanderfolgende Boolean-Operationen auf einem Stern und Kreisen erzeugt. Zeigt, wie man Ergebnis-Formen weiterverwendet und alle verfügbaren Zahnanzahlen unterstützt.
Ergebnis
Verfügbare Zahnanzahlen
PowerPoint stellt nur bestimmte Stern-Formen bereit — nicht alle Zahnzahlen sind möglich:
| Zähne | MsoAutoShapeType |
|---|---|
| 4 | msoShape4pointStar |
| 5 | msoShape5pointStar |
| 6 | msoShape6pointStar |
| 7 | msoShape7pointStar |
| 8 | msoShape8pointStar |
| 10 | msoShape10pointStar |
| 12 | msoShape12pointStar (Standard) |
| 16 | msoShape16pointStar |
| 24 | msoShape24pointStar |
| 32 | msoShape32pointStar |
Warum keine 20 Zähne?
PowerPoint stellt keinen 20-Zacken-Stern bereit — es gibt keinen entsprechenden MsoAutoShapeType-Wert.
20, 28 usw. sind daher nicht möglich.
Vollständige Liste aller Formen: MsoAutoShapeType auf learn.microsoft.com
Code
/* PARAMS */
string tooths = "12"; // 4|5|6|7|8|10|12|16|24|32
float left = 100f;
float top = 80f;
float size = 200f;
var fillColor = System.Drawing.Color.FromArgb(52, 73, 94);
var lineColor = System.Drawing.Color.FromArgb(30, 45, 60);
/* END PARAMS */
int fillRgb = System.Drawing.ColorTranslator.ToOle(fillColor);
int lineRgb = System.Drawing.ColorTranslator.ToOle(lineColor);
float cx = left + size / 2f;
float cy = top + size / 2f;
float sizeSmall = size * 0.5713f;
float sizeBig = size * 0.7143f;
float sizeHole = size * 0.3136f;
void ApplyStyle(dynamic sh)
{
sh.Fill.ForeColor.RGB = fillRgb;
sh.Fill.Transparency = 0f;
sh.Line.Weight = 1.5f;
sh.Line.ForeColor.RGB = lineRgb;
sh.Line.Transparency = 0f;
sh.Line.DashStyle = MsoLineDashStyle.msoLineSolid;
sh.Line.Style = MsoLineStyle.msoLineSingle;
}
MsoAutoShapeType starType;
float adj;
switch (tooths)
{
case "4": starType = MsoAutoShapeType.msoShape4pointStar; adj = 0.25f; break;
case "5": starType = MsoAutoShapeType.msoShape5pointStar; adj = 0.25f; break;
case "6": starType = MsoAutoShapeType.msoShape6pointStar; adj = 0.25f; break;
case "7": starType = MsoAutoShapeType.msoShape7pointStar; adj = 0.25f; break;
case "8": starType = MsoAutoShapeType.msoShape8pointStar; adj = 0.22781f; break;
case "10": starType = MsoAutoShapeType.msoShape10pointStar; adj = 0.23f; break;
case "12": starType = MsoAutoShapeType.msoShape12pointStar; adj = 0.21753f; break;
case "16": starType = MsoAutoShapeType.msoShape16pointStar; adj = 0.22f; break;
case "24": starType = MsoAutoShapeType.msoShape24pointStar; adj = 0.21f; break;
case "32": starType = MsoAutoShapeType.msoShape32pointStar; adj = 0.20f; break;
default: starType = MsoAutoShapeType.msoShape12pointStar; adj = 0.21753f; break;
}
// 1. Stern erstellen
var oStar = ppptools.AddShape(starType, cx - size/2f, cy - size/2f, size, size);
oStar.Adjustments[1] = adj;
ApplyStyle(oStar);
// 2. Kleiner Kreis + Union → Zahnspitzen abrunden
var oSmall = ppptools.AddOval(cx - sizeSmall/2f, cy - sizeSmall/2f, sizeSmall, sizeSmall);
ApplyStyle(oSmall);
oStar.Select(MsoTriState.msoTrue);
oSmall.Select(MsoTriState.msoFalse);
ppptools.Union();
dynamic oUnion = ppptools.GetSelected();
// 3. Grosser Kreis + Intersect → Aussenkontur begrenzen
var oBig = ppptools.AddOval(cx - sizeBig/2f, cy - sizeBig/2f, sizeBig, sizeBig);
ApplyStyle(oBig);
oUnion.Select(MsoTriState.msoTrue);
oBig.Select(MsoTriState.msoFalse);
ppptools.Intersect();
dynamic oIntersect = ppptools.GetSelected();
// 4. Loch-Kreis + Combine → Mitte ausstanzen
var oHole = ppptools.AddOval(cx - sizeHole/2f, cy - sizeHole/2f, sizeHole, sizeHole);
ApplyStyle(oHole);
oIntersect.Select(MsoTriState.msoTrue);
oHole.Select(MsoTriState.msoFalse);
ppptools.Combine();
foreach (dynamic sh in ppptools.GetSelectedRange())
{
sh.Name = "GearWheel_" + tooths;
ApplyStyle(sh);
}
Schritt-für-Schritt-Erklärung
1. Hilfsfunktion ApplyStyle
void ApplyStyle(dynamic sh)
{
sh.Fill.ForeColor.RGB = fillRgb;
...
}
Statt den Stil für jede der vier Formen zu wiederholen, wird er in einer lokalen Funktion gekapselt. Das spart Code und stellt sicher, dass alle Zwischenergebnisse konsistent formatiert sind — was für die Boolean-Operationen wichtig ist (nicht stilisierte Formen können unerwartete Ergebnisse liefern).
Warum void ApplyStyle(dynamic sh) statt Action<dynamic> applyStyle?
→ Action<> ist im System-Namespace, der in Roslyn nicht automatisch importiert wird. Lokale Funktionen funktionieren problemlos. Siehe Scripting-Regeln.
2. Zahnzahl-Auswahl: switch (tooths) mit adj
MsoAutoShapeType starType;
float adj;
switch (tooths)
{
case "12": starType = MsoAutoShapeType.msoShape12pointStar; adj = 0.21753f; break;
...
}
Jede Stern-Form hat eine andere optimale Innenradius-Ratio (adj). Dieser Wert steuert, wie weit die Täler zwischen den Zacken nach innen reichen. Der Adjustment-Wert wird im nächsten Schritt gesetzt:
oStar.Adjustments[1] = adj;
Adjustments ist ein Index-basiertes Array (1-basiert) für form-spezifische Parameter. Bei Sternen steuert [1] das Verhältnis Innenradius/Aussenradius.
3. Operation 1: Union — Zahnspitzen abrunden
// Kleiner Kreis (57,13 % der Grösse) + Union mit Stern
var oSmall = ppptools.AddOval(cx - sizeSmall/2f, cy - sizeSmall/2f, sizeSmall, sizeSmall);
oStar.Select(MsoTriState.msoTrue);
oSmall.Select(MsoTriState.msoFalse);
ppptools.Union();
dynamic oUnion = ppptools.GetSelected();
Ein Kreis, der etwas kleiner als der Stern-Aussenkreis ist (sizeSmall = size * 0.5713f), wird mit dem Stern vereinigt. Dadurch werden die Täler zwischen den Zacken nach aussen aufgefüllt — die Zahnspitzen bleiben, die Einbuchtungen werden runder.
Wichtig: Das Ergebnis wird sofort in dynamic oUnion gespeichert, da die Originale (oStar, oSmall) nach der Operation nicht mehr existieren.
4. Operation 2: Intersect — Aussenkontur begrenzen
// Grosser Kreis (71,43 % der Grösse) + Intersect
var oBig = ppptools.AddOval(cx - sizeBig/2f, cy - sizeBig/2f, sizeBig, sizeBig);
oUnion.Select(MsoTriState.msoTrue);
oBig.Select(MsoTriState.msoFalse);
ppptools.Intersect();
dynamic oIntersect = ppptools.GetSelected();
Ein grosser Kreis (sizeBig = size * 0.7143f) wird mit dem Ergebnis der Union verschnitten: Nur der Bereich, der in beiden Formen liegt, bleibt übrig. Dadurch werden die spitzen Zahnenden abgerundet — das Zahnrad bekommt seine charakteristischen gerundeten Zahnköpfe.
5. Operation 3: Combine — Mittelloch ausstanzen
// Loch-Kreis (31,36 % der Grösse) + Combine
var oHole = ppptools.AddOval(cx - sizeHole/2f, cy - sizeHole/2f, sizeHole, sizeHole);
oIntersect.Select(MsoTriState.msoTrue);
oHole.Select(MsoTriState.msoFalse);
ppptools.Combine();
Zum Abschluss wird das Mittelloch erzeugt: Ein kleiner Kreis (sizeHole = size * 0.3136f) wird mit Combine aus dem Zahnrad ausgestanzt.
Die drei Grössenproportionen
| Variable | Formel | Bedeutung |
|---|---|---|
sizeSmall |
size * 0.5713 |
Füllt Täler auf → rundet Zähne ein |
sizeBig |
size * 0.7143 |
Begrenzt Zahnköpfe → rundet Zähne ab |
sizeHole |
size * 0.3136 |
Mittelloch-Durchmesser |
Diese Proportionen wurden empirisch ermittelt und ergeben für alle Zahnzahlen ein optisch ausgewogenes Zahnrad.
Besonderheiten dieses Beispiels
- Drei aufeinanderfolgende Boolean-Ops — jede nimmt das Ergebnis der vorherigen als Input. Zwischenergebnisse werden in
dynamic-Variablen gespeichert. dynamic oUnion = ppptools.GetSelected()— nach jeder Boolean-Op wird das Ergebnis sofort abgegriffen, bevor die nächste Selektion es überschreibt.Adjustments[1]— form-spezifischer Parameter, der die Innenradius-Ratio des Sterns steuert. Unterschiedliche Werte pro Zahnzahl ergeben gleichmässig aussehende Zähne.- Warum kein 20-Zahn-Zahnrad? — PowerPoint hat keinen
msoShape20pointStar. Auch nicht 9, 11, 13 usw. ApplyStyleauch auf Zwischenformen — damit die Boolean-Ops die Formatierungseigenschaften der Eingabe-Formen konsistent übernehmen.
Zurück: Beispiel 4 — Loch (Combine) · Advanced Snippet Editor Übersicht