33// Created on: 2019-01-13
44
55using System ;
6+ using System . Collections ;
67using System . Collections . Generic ;
78using System . Linq ;
89
10+ using DxfLibrary . GeoMath ;
11+
912namespace DxfLibrary . Geometry
1013{
11- public class GeoPolyline : GeoBase , IGeoLength , IGeoArea
14+ /// <summary>
15+ /// Class that represents a collection of Geolines
16+ /// </summary>
17+ public class GeoPolyline : GeoBase , IGeoLength , IGeoArea , IEnumerable < GeoLine >
1218 {
19+ #region Private Members
20+
1321 /// <summary>
1422 /// Private backing field for lines
1523 /// </summary>
1624 private List < GeoLine > _lines ;
1725
26+ #endregion
27+
28+ #region Constructors
29+
1830 /// <summary>
1931 /// Constructor for the GeoPolyline that takes in Lists of
2032 /// X, y and z coodinates
@@ -27,8 +39,12 @@ public GeoPolyline(List<double> x, List<double> y, List<double> bulges, bool isC
2739 {
2840 // If the numbers do not match then throw an error
2941 if ( x . Count != y . Count || x . Count != bulges . Count )
30- throw new IndexOutOfRangeException ( ) ;
42+ throw new IndexOutOfRangeException ( "All coordinates must be the same size" ) ;
3143
44+ // If there are less than 2 points then the polyline cannot be defined
45+ if ( x . Count < 2 )
46+ throw new ArgumentException ( "Need more than two points to define a polyline" ) ;
47+
3248 _lines = new List < GeoLine > ( ) ;
3349
3450 // Iterate through and create new lines
@@ -50,6 +66,12 @@ public GeoPolyline(List<double> x, List<double> y, List<double> bulges, bool isC
5066 var bulge = new Bulge ( bulges . Last ( ) ) ;
5167 _lines . Add ( new GeoLine ( point0 , point1 , bulge ) ) ;
5268 }
69+
70+ // Determine the draw direction using the first and second
71+ // line by converting them to vectors and crossing them.
72+ if ( _lines . Count > 1 )
73+ DrawDirection = _lines [ 0 ] . ToVector ( )
74+ . Cross ( _lines [ 1 ] . ToVector ( ) ) . Z ;
5375 }
5476
5577 /// <summary>
@@ -62,6 +84,10 @@ public GeoPolyline(List<double> x, List<double> y, bool isClosed)
6284 {
6385 }
6486
87+ #endregion
88+
89+ #region Public Properties
90+
6591 /// <summary>
6692 /// Get the total length of all the lines
6793 /// </summary>
@@ -70,6 +96,76 @@ public GeoPolyline(List<double> x, List<double> y, bool isClosed)
7096 /// <summary>
7197 /// Get the total area of all the lines
7298 /// </summary>
73- public double Area => _lines . Select ( l => l . Area ) . Sum ( ) ;
99+ public double Area => CalcArea ( ) ;
100+
101+ /// <summary>
102+ /// The Draw direction of the polyline.
103+ /// If the value is >0 then the draw direction is counterclockwise
104+ /// If the value is less than 0 then the direction is clockwise
105+ /// </summary>
106+ public double DrawDirection { get ; }
107+
108+ #endregion
109+
110+ #region Public Methods
111+
112+ /// <summary>
113+ /// Get the enumerator for the lines in the polyline
114+ /// </summary>
115+ /// <returns>Returns the Enumberator for the lines in the polyline</returns>
116+ public IEnumerator < GeoLine > GetEnumerator ( )
117+ {
118+ return _lines . GetEnumerator ( ) ;
119+ }
120+
121+ /// <summary>
122+ /// Gets the enumerator for the polyline class
123+ /// </summary>
124+ IEnumerator IEnumerable . GetEnumerator ( ) => GetEnumerator ( ) ;
125+
126+ #endregion
127+
128+ #region Private Methods
129+
130+ private double CalcArea ( )
131+ {
132+ double sum = 0.0d ;
133+
134+ // Need to iterate through the lines to caluclate the
135+ // Total area
136+ foreach ( var segment in _lines )
137+ {
138+ // If the segment does not have a bulge then
139+ // Add the area from the object to the sum
140+ if ( ! segment . HasBulge )
141+ {
142+ sum += segment . Area ;
143+ continue ;
144+ }
145+
146+ // First add the area of the Trapizoid
147+ if ( DrawDirection > 0 )
148+ sum += ( new GeoLine ( segment . Point0 , segment . Point1 ) . Area ) * - 1.0 ;
149+
150+ else if ( DrawDirection < 0 )
151+ sum += new GeoLine ( segment . Point0 , segment . Point1 ) . Area ;
152+
153+ // This value will determine if we are to add or subtract the segment area
154+ var segmentAreaSwtich = DrawDirection * segment . Bulge . Value ;
155+
156+ if ( segmentAreaSwtich > 0 )
157+ sum += segment . Area ;
158+
159+ else if ( segmentAreaSwtich < 0 )
160+ sum -= segment . Area ;
161+
162+ }
163+
164+ return Math . Abs ( sum ) ;
165+ }
166+
167+
168+
169+ #endregion
74170 }
75171}
0 commit comments