Skip to content

Commit

Permalink
Merge pull request #1 from rena0157/develop
Browse files Browse the repository at this point in the history
Adding Area for Polylines with Arcs
  • Loading branch information
rena0157 authored Feb 2, 2019
2 parents 6a81ba2 + bc00d7f commit 54e20ec
Show file tree
Hide file tree
Showing 7 changed files with 441 additions and 22 deletions.
5 changes: 4 additions & 1 deletion src/DxfLibrary/GeoMath/BasicGeometry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ namespace DxfLibrary.GeoMath
/// </summary>
public static class BasicGeometry
{
/// <summary>
/// The Tolerance for floating point numbers in this library.
/// </summary>
public static double Tolerance = 1E-10;

/// <summary>
Expand Down Expand Up @@ -49,7 +52,7 @@ public static double TrapzArea(GeoLine line)
/// <param name="radius">The radius of the circle</param>
/// <param name="angle">The angle that the segment occupies in Radians</param>
/// <returns>The Area of the segment</returns>
public static double CircleSegmentArea(double radius, double angle) => Math.Pow(radius, 2) * (angle - Math.Sin(angle));
public static double CircleSegmentArea(double radius, double angle) => Math.Pow(radius, 2) * 0.5 * (angle - Math.Sin(angle));

#region Unit Conversion

Expand Down
76 changes: 76 additions & 0 deletions src/DxfLibrary/GeoMath/Vector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ public Vector(GeoPoint origin, GeoPoint destination)
Destination = destination;
}

/// <summary>
/// Constructor that creates a vector with its tail at the origin
/// and the destination given by a <see cref="GeoPoint">.
/// </summary>
/// <param name="destination">The GeoPoint for the destination</param>
public Vector(GeoPoint destination) : this(new GeoPoint(0,0), destination)
{

}

#endregion

#region Public Properties
Expand Down Expand Up @@ -94,6 +104,72 @@ public Vector Translate(GeoPoint origin)
new GeoPoint(origin.X + X, origin.Y + Y, origin.Z + Z));
}

/// <summary>
/// Dot product of the vector and another vector
/// </summary>
/// <param name="other">The other vector to dot with</param>
/// <returns>Returns: The result of the dot product</returns>
public double Dot(Vector other) => X * other.X + Y * other.Y + Z * other.Z;

/// <summary>
/// The Cross Product of this vector and another vector.
/// Note that this returns a new vector where this origin is the same
/// as this vector.
/// </summary>
/// <param name="v2">The other vector that is being crossed</param>
/// <returns>Returns: A new vector</returns>
public Vector Cross(Vector v2) => new Vector(Origin,
new GeoPoint(Origin.X + Y*v2.Z - v2.Y*Z,
Origin.Y + v2.X*Z - X*v2.Z,
Origin.Z + (X*v2.Y - v2.X*Y)));

#endregion

#region Overrides

/// <summary>
/// Overloaded operator + for the vector type
/// </summary>
/// <param name="a">The first vector</param>
/// <param name="b">The second vector</param>
/// <returns>Returns a new vector which is the addition of the two vectors</returns>
public static Vector operator +(Vector a, Vector b)
{
return new Vector(new GeoPoint(a.Origin.X + b.Origin.X, a.Origin.Y + b.Origin.Y, a.Origin.Z + b.Origin.Z),
new GeoPoint(a.Destination.X + b.Destination.X,
a.Destination.Y + b.Destination.Y, a.Destination.Z + b.Destination.Z));
}

/// <summary>
/// Equals override for the vector type
/// </summary>
/// <param name="obj">The object that you are comparing</param>
/// <returns>Returns true if the vector is equal to another vector</returns>
public override bool Equals(object obj)
{
var vector = obj as Vector;

if (vector == null)
return false;

return Origin.Equals(vector.Origin) &&
Destination.Equals(vector.Destination);
}

/// <summary>
/// Override for the GetHashCode Type
/// </summary>
/// <returns>Returns: an int which is the hash code for the vector</returns>
public override int GetHashCode()
{
int hash = 983251653;

hash = (hash * 817504243) + Origin.GetHashCode();
hash = (hash * 817504243) + Destination.GetHashCode();

return hash;
}

#endregion

#region UnitVectors
Expand Down
9 changes: 1 addition & 8 deletions src/DxfLibrary/Geometry/Bulge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public Bulge(double bulgeValue)
/// <summary>
/// The Angle of the Bulge in Degrees
/// </summary>
public double AngleDeg => Rad2Deg(Angle);
public double AngleDeg => BasicGeometry.Rad2Deg(Angle);

/// <summary>
/// Distance from the Chord line to the highest point of the arc,
Expand All @@ -61,12 +61,5 @@ public double Sagitta(GeoPoint p0, GeoPoint p1)
/// <returns>The Radius of the Arc</returns>
public double Radius(GeoPoint p0, GeoPoint p1)
=> BasicGeometry.Distance(p0, p1) * 0.5 * (Math.Pow(Value, 2) + 1) / (2 * Value);

/// <summary>
/// Converter for rads to degs
/// </summary>
/// <param name="val">Val in radians</param>
/// <returns>The value in degrees</returns>
private double Rad2Deg(double val) => val * (180 / Math.PI);
}
}
34 changes: 26 additions & 8 deletions src/DxfLibrary/Geometry/GeoLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ public GeoLine(GeoPoint p0, GeoPoint p1, Bulge bulge)
/// </summary>
public Bulge Bulge {get;}

/// <summary>
/// Returns True if the line has a bulge, and false
/// if the file does not have a bulge
/// </summary>
public bool HasBulge => !(BasicGeometry.DoubleCompare(Bulge.Value, 0));

/// <summary>
/// The Length of the Line.
/// </summary>
Expand All @@ -85,7 +91,8 @@ public GeoLine(GeoPoint p0, GeoPoint p1, Bulge bulge)
/// <summary>
/// Area of the Segment. The Area of the segment
/// Is the area of a trapizoid that is bounded by the two points of the
/// line.
/// line. Note that if the segment is an arc then the area is the area
/// bounded by that arc.
/// </summary>
public double Area => CalcArea();

Expand All @@ -101,8 +108,13 @@ public double Radius
/// If the bulge is zero then the angle will return
/// positive infinity
/// </summary>
/// <remarks>
/// If there is no arc then the segment is a line and
/// will then have an angle of PI (180 degrees). This angle will be returned
/// in radians.
/// </remarks>
public double Angle
=> Bulge.Value != 0 ? Bulge.Angle : double.PositiveInfinity;
=> Bulge.Value != 0 ? Bulge.Angle : Math.PI;

#endregion

Expand All @@ -111,7 +123,7 @@ public double Angle
/// <summary>
/// Override of the ToString Method
/// </summary>
/// <returns></returns>
/// <returns>Returns: The Lines points and coordinates</returns>
public override string ToString()
{
return $"P0({Point0.X}, {Point0.Y}, {Point0.Z}), P1({Point1.X}, {Point1.Y}, {Point1.Z})";
Expand All @@ -120,7 +132,10 @@ public override string ToString()
/// <summary>
/// Convert this entity to a vector
/// </summary>
/// <returns>A new vector</returns>
/// <returns>
/// Returns: A new vector that has the origin and destination
/// the same as this lines point 0 and point 1
/// </returns>
public Vector ToVector() => new Vector(Point0, Point1);

#endregion
Expand All @@ -130,7 +145,12 @@ public override string ToString()
/// <summary>
/// Calculate the length of the Segment.
/// </summary>
/// <returns>The length of the line</returns>
/// <remarks>
/// If the bulge value is 0: Returns the length of the line segment
///
/// If the bulge value is not 0: Returns the arc length of the arc segment
/// </remarks>
/// <returns>The length of the segment</returns>
private double CalcLength()
{
// If the line has no bulge then calculate the straight length
Expand All @@ -155,11 +175,9 @@ private double CalcArea()

// If the bulge value is not equal to 0 then return the
// Area of the circle segment
return BasicGeometry.CircleSegmentArea(Bulge.Radius(Point0, Point1), Bulge.Angle);
return Math.Abs(BasicGeometry.CircleSegmentArea(Bulge.Radius(Point0, Point1), Bulge.Angle));
}



#endregion
}
}
102 changes: 99 additions & 3 deletions src/DxfLibrary/Geometry/GeoPolyline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,30 @@
// Created on: 2019-01-13

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

using DxfLibrary.GeoMath;

namespace DxfLibrary.Geometry
{
public class GeoPolyline : GeoBase, IGeoLength, IGeoArea
/// <summary>
/// Class that represents a collection of Geolines
/// </summary>
public class GeoPolyline : GeoBase, IGeoLength, IGeoArea, IEnumerable<GeoLine>
{
#region Private Members

/// <summary>
/// Private backing field for lines
/// </summary>
private List<GeoLine> _lines;

#endregion

#region Constructors

/// <summary>
/// Constructor for the GeoPolyline that takes in Lists of
/// X, y and z coodinates
Expand All @@ -27,8 +39,12 @@ public GeoPolyline(List<double> x, List<double> y, List<double> bulges, bool isC
{
// If the numbers do not match then throw an error
if (x.Count != y.Count || x.Count != bulges.Count)
throw new IndexOutOfRangeException();
throw new IndexOutOfRangeException("All coordinates must be the same size");

// If there are less than 2 points then the polyline cannot be defined
if (x.Count < 2)
throw new ArgumentException("Need more than two points to define a polyline");

_lines = new List<GeoLine>();

// Iterate through and create new lines
Expand All @@ -50,6 +66,12 @@ public GeoPolyline(List<double> x, List<double> y, List<double> bulges, bool isC
var bulge = new Bulge(bulges.Last());
_lines.Add(new GeoLine(point0, point1, bulge));
}

// Determine the draw direction using the first and second
// line by converting them to vectors and crossing them.
if (_lines.Count > 1)
DrawDirection = _lines[0].ToVector()
.Cross( _lines[1].ToVector() ).Z;
}

/// <summary>
Expand All @@ -62,6 +84,10 @@ public GeoPolyline(List<double> x, List<double> y, bool isClosed)
{
}

#endregion

#region Public Properties

/// <summary>
/// Get the total length of all the lines
/// </summary>
Expand All @@ -70,6 +96,76 @@ public GeoPolyline(List<double> x, List<double> y, bool isClosed)
/// <summary>
/// Get the total area of all the lines
/// </summary>
public double Area => _lines.Select(l => l.Area).Sum();
public double Area => CalcArea();

/// <summary>
/// The Draw direction of the polyline.
/// If the value is >0 then the draw direction is counterclockwise
/// If the value is less than 0 then the direction is clockwise
/// </summary>
public double DrawDirection {get;}

#endregion

#region Public Methods

/// <summary>
/// Get the enumerator for the lines in the polyline
/// </summary>
/// <returns>Returns the Enumberator for the lines in the polyline</returns>
public IEnumerator<GeoLine> GetEnumerator()
{
return _lines.GetEnumerator();
}

/// <summary>
/// Gets the enumerator for the polyline class
/// </summary>
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

#endregion

#region Private Methods

private double CalcArea()
{
double sum = 0.0d;

// Need to iterate through the lines to caluclate the
// Total area
foreach(var segment in _lines)
{
// If the segment does not have a bulge then
// Add the area from the object to the sum
if (!segment.HasBulge)
{
sum += segment.Area;
continue;
}

// First add the area of the Trapizoid
if (DrawDirection > 0)
sum += (new GeoLine(segment.Point0, segment.Point1).Area) * -1.0;

else if (DrawDirection < 0)
sum += new GeoLine(segment.Point0, segment.Point1).Area;

// This value will determine if we are to add or subtract the segment area
var segmentAreaSwtich = DrawDirection * segment.Bulge.Value;

if (segmentAreaSwtich > 0)
sum += segment.Area;

else if (segmentAreaSwtich < 0)
sum -= segment.Area;

}

return Math.Abs(sum);
}



#endregion
}
}
Loading

0 comments on commit 54e20ec

Please sign in to comment.