Skip to content

Commit

Permalink
Merge pull request #494 from hypar-io/profile-unionall
Browse files Browse the repository at this point in the history
Add Profile.UnionAll
  • Loading branch information
andrewheumann authored Jan 27, 2021
2 parents babe986 + b1e6ea2 commit 71abe93
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

### Added

- `Profile.UnionAll(...)` - Create a new set of profiles, merging any overlapping profiles and preserving internal voids.
- `Polyline.SharedSegments()` - Enables search for segments shared between two polylines.
- `Polyline.TransformSegment(...)` - Allows transforms for individual polyline segments. May be optionally flagged as polygon and/or planar motion.

Expand Down
44 changes: 44 additions & 0 deletions Elements/src/Geometry/Profile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -314,5 +314,49 @@ public bool Contains(Vector3 point, out Containment containment)
}
return Polygon.Contains(allLines, point, out containment);
}

/// <summary>
/// Perform a union operation on a set of multiple profiles.
/// </summary>
/// <param name="profiles">The profiles with which to create a union.</param>
/// <param name="tolerance">An optional tolerance.</param>
/// <returns>A new list of profiles comprising the union of all input profiles.</returns>
public static List<Profile> UnionAll(IEnumerable<Profile> profiles, double tolerance = Vector3.EPSILON)
{
Clipper clipper = new Clipper();
foreach (var profile in profiles)
{
var subjectPolygons = new List<Polygon> { profile.Perimeter };
if (profile.Voids != null && profile.Voids.Count > 0)
{
subjectPolygons.AddRange(profile.Voids);
}
var clipperPaths = subjectPolygons.Select(s => s.ToClipperPath(tolerance)).ToList();
clipper.AddPaths(clipperPaths, PolyType.ptSubject, true);
}
PolyTree solution = new PolyTree();
clipper.Execute(ClipType.ctUnion, solution, PolyFillType.pftPositive);
if (solution.ChildCount == 0)
{
return null;
}
var joinedProfiles = new List<Profile>();
foreach (var result in solution.Childs)
{
var perimeter = PolygonExtensions.ToPolygon(result.Contour, tolerance);
List<Polygon> voidCrvs = new List<Polygon>();
if (result.ChildCount > 0)
{
foreach (var child in result.Childs)
{
var voidCrv = PolygonExtensions.ToPolygon(child.Contour, tolerance);
voidCrvs.Add(voidCrv);
}

}
joinedProfiles.Add(new Profile(perimeter, voidCrvs, Guid.NewGuid(), null));
}
return joinedProfiles;
}
}
}
23 changes: 23 additions & 0 deletions Elements/test/ProfileTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,29 @@ public void ProfileMultipleUnion()
Assert.Equal(8, seed.Voids.Count());
}

[Fact]
public void ProfileUnionAll()
{
this.Name = "ProfileUnionAll";
var outer1 = new Circle(Vector3.Origin, 5).ToPolygon(10);
var inner1 = new Circle(Vector3.Origin, 4).ToPolygon(10);
var outer2 = new Circle(new Vector3(9, 0, 0), 5).ToPolygon(10);
var inner2 = new Circle(new Vector3(9, 0, 0), 4).ToPolygon(10);
var outer3 = new Circle(new Vector3(4.5, 12, 0), 5).ToPolygon(10);
var inner3 = new Circle(new Vector3(4.5, 12, 0), 4).ToPolygon(10);
var p1 = new Profile(outer1, inner1);
var p2 = new Profile(outer2, inner2);
var p3 = new Profile(outer3, inner3);
var union = Elements.Geometry.Profile.UnionAll(new[] { p1, p2, p3 });
foreach (var profile in union)
{
var floor = new Floor(profile, 1);
this.Model.AddElement(floor);
}
Assert.Equal(2, union.Count);

}

[Fact]
public void VoidsOrientedCorrectly()
{
Expand Down

0 comments on commit 71abe93

Please sign in to comment.