@@ -26,10 +26,10 @@ public static class PolylineAlgorithm
26
26
/// <returns>Returns coordinates.</returns>
27
27
/// <exception cref="ArgumentException">If polyline argument is null -or- empty char array.</exception>
28
28
/// <exception cref="InvalidOperationException">If polyline representation is not in correct format.</exception>
29
- public static IEnumerable < ( double Latitude , double Longitude ) > Decode ( char [ ] polyline )
29
+ public static IEnumerable < ( double Latitude , double Longitude ) > Decode ( string polyline )
30
30
{
31
31
// Checking null and at least one character
32
- if ( polyline == null || ! polyline . Any ( ) )
32
+ if ( polyline == null || polyline . Length == 0 )
33
33
{
34
34
throw new ArgumentException ( ExceptionMessageResource . ArgumentCannotBeNullOrEmpty , nameof ( polyline ) ) ;
35
35
}
@@ -54,14 +54,46 @@ public static class PolylineAlgorithm
54
54
throw new InvalidOperationException ( ExceptionMessageResource . PolylineCharArrayIsMalformed ) ;
55
55
}
56
56
57
- var coordinate = ( GetDoubleRepresentation ( latitude ) , GetDoubleRepresentation ( longitude ) ) ;
57
+ var coordinate = ( GetCoordinate ( latitude ) , GetCoordinate ( longitude ) ) ;
58
58
59
+ // Validating decoded coordinate. If not valid exception is thrown
59
60
if ( ! CoordinateValidator . IsValid ( coordinate ) )
60
61
{
61
62
throw new InvalidOperationException ( ExceptionMessageResource . PolylineCharArrayIsMalformed ) ;
62
63
}
63
64
64
65
yield return coordinate ;
66
+
67
+ #region Local functions
68
+
69
+ bool TryCalculateNext ( string polyline , ref int index , ref int value )
70
+ {
71
+ // Local variable initialization
72
+ int chunk ;
73
+ int sum = 0 ;
74
+ int shifter = 0 ;
75
+
76
+ do
77
+ {
78
+ chunk = polyline [ index ++ ] - Constants . ASCII . QuestionMark ;
79
+ sum |= ( chunk & Constants . ASCII . UnitSeparator ) << shifter ;
80
+ shifter += Constants . ShiftLength ;
81
+ } while ( chunk >= Constants . ASCII . Space && index < polyline . Length ) ;
82
+
83
+ if ( index >= polyline . Length && chunk >= Constants . ASCII . Space )
84
+ return false ;
85
+
86
+ value += ( sum & 1 ) == 1 ? ~ ( sum >> 1 ) : sum >> 1 ;
87
+
88
+ return true ;
89
+ }
90
+
91
+ double GetCoordinate ( int value )
92
+ {
93
+ return Convert . ToDouble ( value ) / Constants . Precision ;
94
+ }
95
+
96
+ #endregion
65
97
}
66
98
}
67
99
@@ -74,139 +106,78 @@ public static class PolylineAlgorithm
74
106
/// <exception cref="AggregateException">If one or more coordinate is out of range</exception>
75
107
public static string Encode ( IEnumerable < ( double Latitude , double Longitude ) > coordinates )
76
108
{
77
- if ( coordinates == null || ! coordinates . Any ( ) )
109
+ if ( coordinates == null || ! coordinates . GetEnumerator ( ) . MoveNext ( ) )
78
110
{
79
111
throw new ArgumentException ( ExceptionMessageResource . ArgumentCannotBeNullOrEmpty , nameof ( coordinates ) ) ;
80
112
}
81
113
82
- // Ensuring coordinates are valid, otherwise throws an aggregate exception
83
- EnsureCoordinates ( coordinates ) ;
114
+ // Validate collection of coordinates
115
+ if ( ! TryValidate ( coordinates , out var exceptions ) )
116
+ {
117
+ throw new AggregateException ( exceptions ) ;
118
+ }
84
119
85
120
// Initializing local variables
86
121
int previousLatitude = 0 ;
87
122
int previousLongitude = 0 ;
88
- var sb = _pool . Get ( ) ;
123
+ var sb = new StringBuilder ( coordinates . Count ( ) * 5 ) ;
89
124
90
125
// Looping over coordinates and building encoded result
91
126
foreach ( var coordinate in coordinates )
92
127
{
93
- int latitude = GetIntegerRepresentation ( coordinate . Latitude ) ;
94
- int longitude = GetIntegerRepresentation ( coordinate . Longitude ) ;
128
+ int latitude = Round ( coordinate . Latitude ) ;
129
+ int longitude = Round ( coordinate . Longitude ) ;
95
130
96
- sb . Append ( GetEncodedCharacters ( latitude - previousLatitude ) . ToArray ( ) ) ;
97
- sb . Append ( GetEncodedCharacters ( longitude - previousLongitude ) . ToArray ( ) ) ;
131
+ sb . Append ( GetSequence ( latitude - previousLatitude ) . ToArray ( ) ) ;
132
+ sb . Append ( GetSequence ( longitude - previousLongitude ) . ToArray ( ) ) ;
98
133
99
134
previousLatitude = latitude ;
100
135
previousLongitude = longitude ;
101
136
}
102
137
103
- var result = sb . ToString ( ) ;
104
-
105
- _pool . Return ( sb ) ;
106
-
107
- return result ;
108
- }
138
+ return sb . ToString ( ) ;
109
139
110
- /// <summary>
111
- /// Method performs coordinates validation. Throws exception, if invalid coordinate is found
112
- /// </summary>
113
- /// <param name="coordinates">Coordinates to validate</param>
114
- /// <exception cref="AggregateException">If one or more coordinate is out of range -or- invalid</exception>
115
- private static void EnsureCoordinates ( IEnumerable < ( double Latitude , double Longitude ) > coordinates )
116
- {
117
- // Selecting invalid coordinates
118
- var invalidCoordinates = coordinates
119
- . Where ( c => ! CoordinateValidator . IsValid ( c ) ) ;
140
+ #region Local functions
120
141
121
- // If any invalid coordinates exists throw an aggregate exception with inner argument out of range exception
122
- if ( invalidCoordinates . Any ( ) )
142
+ bool TryValidate ( IEnumerable < ( double Latitude , double Longitude ) > collection , out ICollection < CoordinateValidationException > exceptions )
123
143
{
124
- throw new AggregateException (
125
- ExceptionMessageResource . AggregateExceptionCoordinatesAreInvalidErrorMessage ,
126
- invalidCoordinates
127
- . Select ( c =>
128
- new ArgumentOutOfRangeException (
129
- string . Format (
130
- ExceptionMessageResource . ArgumentExceptionCoordinateIsOutOfRangeErrorMessageFormat ,
131
- c . Latitude ,
132
- c . Longitude
133
- )
134
- )
135
- )
136
- ) ;
137
- }
138
- }
144
+ exceptions = new List < CoordinateValidationException > ( collection . Count ( ) ) ;
139
145
140
- /// <summary>
141
- ///
142
- /// </summary>
143
- /// <param name="value">Rounded integer representation of precise double value</param>
144
- /// <returns>Returns value with specific precision. See <see cref="Constants.Precision"/></returns>
145
- private static double GetDoubleRepresentation ( int value )
146
- {
147
- return Convert . ToDouble ( value ) / Constants . Precision ;
148
- }
149
-
150
- /// <summary>
151
- /// Method converts value to polyline encoded characters
152
- /// </summary>
153
- /// <param name="value">Difference between current and previous latitude or longitude value</param>
154
- private static IEnumerable < char > GetEncodedCharacters ( int value )
155
- {
156
- int shifted = value << 1 ;
157
- if ( value < 0 )
158
- shifted = ~ shifted ;
146
+ foreach ( var item in collection )
147
+ {
148
+ if ( ! CoordinateValidator . IsValid ( item ) )
149
+ {
150
+ exceptions . Add ( new CoordinateValidationException ( item . Latitude , item . Longitude ) ) ;
151
+ }
152
+ }
159
153
160
- int rem = shifted ;
154
+ return ! exceptions . GetEnumerator ( ) . MoveNext ( ) ;
155
+ }
161
156
162
- while ( rem >= Constants . ASCII . Space )
157
+ int Round ( double value )
163
158
{
164
- yield return ( char ) ( ( Constants . ASCII . Space | rem & Constants . ASCII . UnitSeparator ) + Constants . ASCII . QuestionMark ) ;
165
-
166
- rem >>= Constants . ShiftLength ;
159
+ return ( int ) Math . Round ( value * Constants . Precision ) ;
167
160
}
168
161
169
- yield return ( char ) ( rem + Constants . ASCII . QuestionMark ) ;
170
- }
171
-
172
- /// <summary>
173
- /// Method
174
- /// </summary>
175
- /// <param name="value">Precise double representation</param>
176
- /// <returns></returns>
177
- private static int GetIntegerRepresentation ( double value )
178
- {
179
- return ( int ) Math . Round ( value * Constants . Precision ) ;
180
- }
181
-
182
- /// <summary>
183
- /// Tries to calculate next integer representation of encoded polyline part
184
- /// </summary>
185
- /// <param name="polyline">The <see cref="char[]"/></param>
186
- /// <param name="index">The <see cref="int"/></param>
187
- /// <param name="value">The <see cref="int"/></param>
188
- /// <returns>The <see cref="bool"/></returns>
189
- private static bool TryCalculateNext ( char [ ] polyline , ref int index , ref int value )
190
- {
191
- // Local variable initialization
192
- int chunk ;
193
- int sum = 0 ;
194
- int shifter = 0 ;
162
+ IEnumerable < char > GetSequence ( int value )
163
+ {
164
+ int shifted = value << 1 ;
165
+ if ( value < 0 )
166
+ shifted = ~ shifted ;
195
167
168
+ int rem = shifted ;
196
169
197
- do
198
- {
199
- chunk = polyline [ index ++ ] - Constants . ASCII . QuestionMark ;
200
- sum |= ( chunk & Constants . ASCII . UnitSeparator ) << shifter ;
201
- shifter += Constants . ShiftLength ;
202
- } while ( chunk >= Constants . ASCII . Space && index < polyline . Length ) ;
170
+ while ( rem >= Constants . ASCII . Space )
171
+ {
172
+ yield return ( char ) ( ( Constants . ASCII . Space | rem & Constants . ASCII . UnitSeparator ) + Constants . ASCII . QuestionMark ) ;
203
173
204
- if ( index >= polyline . Length && chunk > = Constants . ASCII . Space )
205
- return false ;
174
+ rem >> = Constants . ShiftLength ;
175
+ }
206
176
207
- value += ( sum & 1 ) == 1 ? ~ ( sum >> 1 ) : sum >> 1 ;
177
+ yield return ( char ) ( rem + Constants . ASCII . QuestionMark ) ;
178
+ }
208
179
209
- return true ;
180
+ #endregion
210
181
}
211
182
}
212
183
}
0 commit comments