Example 5 — Gear Wheel
The most complex example: a gear wheel is created through three consecutive Boolean operations on a star shape and circles. Demonstrates how to chain result shapes and support all available tooth counts.
Result
Available Tooth Counts
PowerPoint only provides specific star shapes — not all tooth counts are possible:
| Teeth | MsoAutoShapeType |
|---|---|
| 4 | msoShape4pointStar |
| 5 | msoShape5pointStar |
| 6 | msoShape6pointStar |
| 7 | msoShape7pointStar |
| 8 | msoShape8pointStar |
| 10 | msoShape10pointStar |
| 12 | msoShape12pointStar (default) |
| 16 | msoShape16pointStar |
| 24 | msoShape24pointStar |
| 32 | msoShape32pointStar |
Why no 20 teeth?
PowerPoint provides no 20-point star — there is no corresponding MsoAutoShapeType value.
20, 28, etc. are therefore not possible.
Full list of all shapes: MsoAutoShapeType on 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. Star
var oStar = ppptools.AddShape(starType, cx - size/2f, cy - size/2f, size, size);
oStar.Adjustments[1] = adj;
ApplyStyle(oStar);
// 2. Small circle + Union → round off teeth valleys
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. Large circle + Intersect → limit outer shape
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. Hole circle + Combine → punch out center
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);
}
Step-by-Step Explanation
1. The ApplyStyle Helper Function
void ApplyStyle(dynamic sh)
{
sh.Fill.ForeColor.RGB = fillRgb;
...
}
Instead of repeating the styling for each of the four shapes, it is encapsulated in a local function. This saves code and ensures all intermediate shapes are consistently styled — which matters for Boolean operations (inconsistently styled shapes can produce unexpected results).
Why void ApplyStyle(dynamic sh) instead of Action<dynamic> applyStyle?
→ Action<> is in the System namespace, which is not automatically imported in Roslyn. Local functions work without issue. See Scripting Rules.
2. Tooth Count Selection: switch (tooths) with adj
MsoAutoShapeType starType;
float adj;
switch (tooths)
{
case "12": starType = MsoAutoShapeType.msoShape12pointStar; adj = 0.21753f; break;
...
}
Each star shape has a different optimal inner radius ratio (adj). This value controls how far the valleys between the star's points reach inward. The adjustment is applied in the next step:
oStar.Adjustments[1] = adj;
Adjustments is a 1-based index array for shape-specific parameters. For stars, [1] controls the inner radius / outer radius ratio.
3. Operation 1: Union — Round Off the Tooth Valleys
// Small circle (57.13% of size) + Union with star
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();
A circle slightly smaller than the star's outer circumscribed circle (sizeSmall = size * 0.5713f) is merged with the star. This fills in the valleys between the teeth — the tooth tips remain while the indentations become rounder.
Important: The result is immediately stored in dynamic oUnion, since the originals (oStar, oSmall) no longer exist after the operation.
4. Operation 2: Intersect — Constrain the Outer Shape
// Large circle (71.43% of size) + 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();
A large circle (sizeBig = size * 0.7143f) is intersected with the Union result: only the area that lies within both shapes remains. This rounds off the sharp tooth tips — the gear wheel gets its characteristic rounded tooth crowns.
5. Operation 3: Combine — Punch Out the Center Hole
// Hole circle (31.36% of size) + Combine
var oHole = ppptools.AddOval(cx - sizeHole/2f, cy - sizeHole/2f, sizeHole, sizeHole);
oIntersect.Select(MsoTriState.msoTrue);
oHole.Select(MsoTriState.msoFalse);
ppptools.Combine();
Finally, the center hole is created: a small circle (sizeHole = size * 0.3136f) is punched out of the gear wheel using Combine.
The Three Size Proportions
| Variable | Formula | Purpose |
|---|---|---|
sizeSmall |
size * 0.5713 |
Fills valleys → rounds tooth roots inward |
sizeBig |
size * 0.7143 |
Constrains tooth tips → rounds tooth crowns outward |
sizeHole |
size * 0.3136 |
Center hole diameter |
These proportions were determined empirically and produce a visually balanced gear wheel for all available tooth counts.
What's Special About This Example
- Three chained Boolean operations — each takes the previous result as input. Intermediate results are stored in
dynamicvariables. dynamic oUnion = ... ShapeRange[1]— after each Boolean op, the result is immediately captured before the next selection replaces it.Adjustments[1]— shape-specific parameter that controls the star's inner radius ratio. Different values per tooth count produce evenly proportioned teeth.- Why no 20-tooth gear? — PowerPoint has no
msoShape20pointStar. Also missing: 9, 11, 13, etc. ApplyStyleon intermediate shapes too — so that Boolean operations consistently inherit the formatting properties from the input shapes.
Back: Example 4 — Hole (Combine) · Advanced Snippet Editor Overview