Skip to content

Commit 3142c01

Browse files
Make methods pure
1 parent 8da8f61 commit 3142c01

4 files changed

Lines changed: 59 additions & 15 deletions

File tree

src/PolygonClipper/Contour.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,33 @@ public void Clear()
251251
/// <param name="index">The index of the hole to add.</param>
252252
public void AddHoleIndex(int index) => this.holeIndices.Add(index);
253253

254+
/// <summary>
255+
/// Creates a deep copy of this contour.
256+
/// </summary>
257+
/// <param name="contourIndexOffset">
258+
/// Offset applied to parent and hole contour indices so copied topology remains valid
259+
/// when inserted into another polygon.
260+
/// </param>
261+
/// <returns>A detached contour copy.</returns>
262+
internal Contour DeepClone(int contourIndexOffset = 0)
263+
{
264+
Contour clone = new(this.vertices.Count)
265+
{
266+
ParentIndex = this.ParentIndex is int parentIndex ? parentIndex + contourIndexOffset : null,
267+
Depth = this.Depth,
268+
hasCachedOrientation = this.hasCachedOrientation,
269+
cachedCounterClockwise = this.cachedCounterClockwise
270+
};
271+
272+
clone.vertices.AddRange(this.vertices);
273+
for (int i = 0; i < this.holeIndices.Count; i++)
274+
{
275+
clone.holeIndices.Add(this.holeIndices[i] + contourIndexOffset);
276+
}
277+
278+
return clone;
279+
}
280+
254281
/// <inheritdoc/>
255282
public IEnumerator<Vertex> GetEnumerator()
256283
=> ((IEnumerable<Vertex>)this.vertices).GetEnumerator();

src/PolygonClipper/Polygon.cs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,13 @@ public Contour this[int index]
7676
/// <param name="polygon">The polygon to join.</param>
7777
public void Join(Polygon polygon)
7878
{
79-
int size = this.Count;
80-
for (int i = 0; i < polygon.contours.Count; ++i)
81-
{
82-
Contour contour = polygon.contours[i];
83-
this.Add(contour);
84-
this.GetLastContour().ClearHoles();
79+
ArgumentNullException.ThrowIfNull(polygon);
8580

86-
for (int j = 0; j < contour.HoleCount; ++j)
87-
{
88-
this.GetLastContour().AddHoleIndex(contour.GetHoleIndex(j) + size);
89-
}
81+
int sourceCount = polygon.contours.Count;
82+
int contourIndexOffset = this.contours.Count;
83+
for (int i = 0; i < sourceCount; ++i)
84+
{
85+
this.contours.Add(polygon.contours[i].DeepClone(contourIndexOffset));
9086
}
9187
}
9288

@@ -141,6 +137,21 @@ public void Translate(double x, double y)
141137
/// </summary>
142138
public void Clear() => this.contours.Clear();
143139

140+
/// <summary>
141+
/// Creates a deep copy of this polygon and all of its contours.
142+
/// </summary>
143+
/// <returns>A detached polygon copy.</returns>
144+
internal Polygon DeepClone()
145+
{
146+
Polygon clone = new(this.contours.Count);
147+
for (int i = 0; i < this.contours.Count; i++)
148+
{
149+
clone.contours.Add(this.contours[i].DeepClone());
150+
}
151+
152+
return clone;
153+
}
154+
144155
/// <inheritdoc/>
145156
public IEnumerator<Contour> GetEnumerator()
146157
=> ((IEnumerable<Contour>)this.contours).GetEnumerator();

src/PolygonClipper/PolygonClipper.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -455,13 +455,13 @@ private static bool TryTrivialOperationForEmptyPolygons(
455455

456456
if (operation == BooleanOperation.Difference)
457457
{
458-
result = subject;
458+
result = subject.DeepClone();
459459
return true;
460460
}
461461

462462
if (operation is BooleanOperation.Union or BooleanOperation.Xor)
463463
{
464-
result = subject.Count == 0 ? clipping : subject;
464+
result = subject.Count == 0 ? clipping.DeepClone() : subject.DeepClone();
465465
return true;
466466
}
467467
}
@@ -505,13 +505,14 @@ private static bool TryTrivialOperationForNonOverlappingBoundingBoxes(
505505
// The bounding boxes do not overlap
506506
if (operation == BooleanOperation.Difference)
507507
{
508-
result = subject;
508+
result = subject.DeepClone();
509509
return true;
510510
}
511511

512512
if (operation is BooleanOperation.Union or BooleanOperation.Xor)
513513
{
514-
result = subject;
514+
result = new(subject.Count + clipping.Count);
515+
result.Join(subject);
515516
result.Join(clipping);
516517
return true;
517518
}

src/PolygonClipper/PolygonStroker.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,12 @@ public Polygon Stroke(Polygon polygon)
229229
Polygon stroked = this.ProcessPathToPolygon(contour, isClosed);
230230
if (stroked.Count > 0)
231231
{
232-
allContours.Join(stroked);
232+
// Stroked contours are produced as fresh objects; append by reference
233+
// here to avoid an unnecessary clone step in the hot path.
234+
for (int j = 0; j < stroked.Count; j++)
235+
{
236+
allContours.Add(stroked[j]);
237+
}
233238
}
234239
}
235240

0 commit comments

Comments
 (0)