Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/hypar-io/Elements
Browse files Browse the repository at this point in the history
  • Loading branch information
ikeough committed Jan 27, 2020
2 parents e069ebc + 5c4d765 commit bad388b
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 26 deletions.
18 changes: 4 additions & 14 deletions src/Elements/Geometry/Polygon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -393,23 +393,13 @@ public IList<Polygon> XOR(Polygon polygon)
/// </summary>
/// <param name="offset">The amount to offset.</param>
/// <returns>A new Polygon offset by offset.</returns>
public Polygon[] Offset(double offset)
///
public override Polygon[] Offset(double offset, EndType endType = EndType.ClosedPolygon)
{
var path = this.ToClipperPath();

var solution = new List<List<IntPoint>>();
var co = new ClipperOffset();
co.AddPath(path, JoinType.jtMiter, EndType.etClosedPolygon);
co.Execute(ref solution, offset * scale); // important, scale also used here

var result = new Polygon[solution.Count];
for(var i=0; i<result.Length; i++)
{
result[i] = solution[i].ToPolygon();
}
return result;
return base.Offset(offset, endType);
}


/// <summary>
/// Get a collection a lines representing each segment of this polyline.
/// </summary>
Expand Down
102 changes: 91 additions & 11 deletions src/Elements/Geometry/Polyline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using ClipperLib;

namespace Elements.Geometry
{
Expand All @@ -10,15 +11,18 @@ namespace Elements.Geometry
/// </summary>
public partial class Polyline : ICurve
{

internal const double scale = 1024.0;

/// <summary>
/// Calculate the length of the polygon.
/// </summary>
public override double Length()
{
var length = 0.0;
for(var i=0; i<this.Vertices.Count-1; i++)
for (var i = 0; i < this.Vertices.Count - 1; i++)
{
length += this.Vertices[i].DistanceTo(this.Vertices[i+1]);
length += this.Vertices[i].DistanceTo(this.Vertices[i + 1]);
}
return length;
}
Expand Down Expand Up @@ -104,7 +108,7 @@ public override Transform TransformAt(double u)
// to one of the vertices.
Vector3 a = new Vector3();
var isEqualToVertex = false;
foreach(var v in this.Vertices)
foreach (var v in this.Vertices)
{
if (v.Equals(o))
{
Expand Down Expand Up @@ -229,9 +233,9 @@ protected void CheckCoincidenceAndThrow(IList<Vector3> vertices)
/// </summary>
internal static void CheckSegmentLengthAndThrow(IList<Line> segments)
{
foreach(var s in segments)
foreach (var s in segments)
{
if(s.Length() == 0)
if (s.Length() == 0)
{
throw new ArgumentException("A segment fo the polyline has zero length.");
}
Expand All @@ -247,16 +251,16 @@ internal static void CheckSelfIntersectionAndThrow(Transform t, IList<Line> segm
{
var segmentsTrans = new List<Line>();

foreach(var l in segments)
foreach (var l in segments)
{
segmentsTrans.Add(t.OfLine(l));
};

for(var i=0; i<segmentsTrans.Count; i++)
for (var i = 0; i < segmentsTrans.Count; i++)
{
for(var j=0; j<segmentsTrans.Count; j++)
for (var j = 0; j < segmentsTrans.Count; j++)
{
if(i == j)
if (i == j)
{
// Don't check against itself.
continue;
Expand Down Expand Up @@ -300,12 +304,12 @@ private Transform CreateOthogonalTransform(int i, Vector3 a)
if (i == 0)
{
b = this.Vertices[i + 1];
return new Transform(a, (a-b).Normalized());
return new Transform(a, (a - b).Normalized());
}
else if (i == this.Vertices.Count - 1)
{
b = this.Vertices[i - 1];
return new Transform(a, (b-a).Normalized());
return new Transform(a, (b - a).Normalized());
}
else
{
Expand Down Expand Up @@ -350,5 +354,81 @@ private Vector3 PointAtInternal(double u, out int segmentIndex)
segmentIndex = this.Vertices.Count - 1;
return this.End;
}

/// <summary>
/// Offset this polyline by the specified amount.
/// </summary>
/// <param name="offset">The amount to offset.</param>
/// <returns>A new closed Polygon offset in all directions by offset from the polyline.</returns>
public virtual Polygon[] Offset(double offset, EndType endType)
{
var path = this.ToClipperPath();

var solution = new List<List<IntPoint>>();
var co = new ClipperOffset();
ClipperLib.EndType clEndType;
switch (endType)
{
case EndType.Butt:
clEndType = ClipperLib.EndType.etOpenButt;
break;
case EndType.ClosedPolygon:
clEndType = ClipperLib.EndType.etClosedPolygon;
break;
case EndType.Square:
default:
clEndType = ClipperLib.EndType.etOpenSquare;
break;
}
co.AddPath(path, JoinType.jtMiter, clEndType);
co.Execute(ref solution, offset * scale); // important, scale also used here

var result = new Polygon[solution.Count];
for (var i = 0; i < result.Length; i++)
{
result[i] = solution[i].ToPolygon();
}
return result;
}
}

/// <summary>
/// Polyline extension methods.
/// </summary>
internal static class PolylineExtensions
{
/// <summary>
/// Construct a clipper path from a Polygon.
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
internal static List<IntPoint> ToClipperPath(this Polyline p)
{
var path = new List<IntPoint>();
foreach (var v in p.Vertices)
{
path.Add(new IntPoint(v.X * Polyline.scale, v.Y * Polyline.scale));
}
return path;
}
}

/// <summary>
/// Offset end types
/// </summary>
public enum EndType
{
/// <summary>
/// Open ends are extended by the offset distance and squared off
/// </summary>
Square,
/// <summary>
/// Ends are squared off with no extension
/// </summary>
Butt,
/// <summary>
/// If open, ends are joined and treated as a closed polygon
/// </summary>
ClosedPolygon,
}
}
2 changes: 2 additions & 0 deletions src/Elements/Geometry/Vector3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,8 @@ public static class Vector3Extensions
/// <param name="points"></param>
public static bool AreCoplanar(this IList<Vector3> points)
{
if (points.Count < 3) return true;

//TODO: https://github.com/hypar-io/sdk/issues/54
// Ensure that all triple products are equal to 0.
// a.Dot(b.Cross(c));
Expand Down
21 changes: 20 additions & 1 deletion test/Elements.Tests/PolylineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,28 @@ public void Polyline_Construct()
var c = new Vector3(3, 5);
var d = new Vector3(2, 1);

var pline = new Polyline(new[]{a,b,c,d});
var pline = new Polyline(new[] { a, b, c, d });
Assert.Equal(4, pline.Vertices.Count);
Assert.Equal(3, pline.Segments().Length);
}

[Fact]
public void Polyline_ClosedOffset()
{
var length = 10;
var offsetAmt = 1;
var a = new Vector3();
var b = new Vector3(length, 0);
var pline = new Polyline(new[] { a, b });
var offsetResults = pline.Offset(offsetAmt, EndType.Square);
Assert.Equal(1, offsetResults.Length);
var offsetResult = offsetResults[0];
Assert.Equal(4, offsetResult.Vertices.Count);
// offsets to a rectangle that's offsetAmt longer than the segment in
// each direction, and 2x offsetAmt in width, so the long sides are
// each length + 2x offsetAmt, and the short sides are each 2x offsetAmt.
var targetLength = 2 * length + 8 * offsetAmt;
Assert.Equal(targetLength, offsetResult.Length(), 2);
}
}
}

0 comments on commit bad388b

Please sign in to comment.