markus / MarkupToPDF / Controls / Common / StringToPathConverter.cs @ 24c5e56c
이력 | 보기 | 이력해설 | 다운로드 (23.7 KB)
1 | 787a4489 | KangIngu | using System; |
---|---|---|---|
2 | using System.Net; |
||
3 | using System.Windows; |
||
4 | using System.Windows.Controls; |
||
5 | using System.Windows.Documents; |
||
6 | using System.Windows.Ink; |
||
7 | using System.Windows.Input; |
||
8 | using System.Windows.Media; |
||
9 | using System.Windows.Media.Animation; |
||
10 | using System.Windows.Shapes; |
||
11 | using System.Windows.Data; |
||
12 | using System.Globalization; |
||
13 | |||
14 | namespace MarkupToPDF.Controls.Common |
||
15 | { |
||
16 | public class StringToPathConverter : IValueConverter, IDisposable |
||
17 | { |
||
18 | #region Const & Private Variables |
||
19 | const bool AllowSign = true; |
||
20 | const bool AllowComma = true; |
||
21 | const bool IsFilled = true; |
||
22 | const bool IsClosed = true; |
||
23 | |||
24 | IFormatProvider _formatProvider; |
||
25 | |||
26 | PathFigure _figure = null; // Figure object, which will accept parsed segments |
||
27 | string _pathString; // Input string to be parsed |
||
28 | int _pathLength; |
||
29 | int _curIndex; // Location to read next character from |
||
30 | bool _figureStarted; // StartFigure is effective |
||
31 | |||
32 | Point _lastStart; // Last figure starting point |
||
33 | Point _lastPoint; // Last point |
||
34 | Point _secondLastPoint; // The point before last point |
||
35 | |||
36 | char _token; // Non whitespace character returned by ReadToken |
||
37 | #endregion |
||
38 | |||
39 | #region Public Functionality |
||
40 | /// <summary> |
||
41 | /// Main conversion routine - converts string path data definition to PathGeometry object |
||
42 | /// </summary> |
||
43 | /// <param name="path">String with path data definition</param> |
||
44 | /// <returns>PathGeometry object created from string definition</returns> |
||
45 | public PathGeometry Convert(string path) |
||
46 | { |
||
47 | if (null == path) |
||
48 | throw new ArgumentException("Path string cannot be null!"); |
||
49 | |||
50 | if (path.Length == 0) |
||
51 | throw new ArgumentException("Path string cannot be empty!"); |
||
52 | |||
53 | return parse(path); |
||
54 | } |
||
55 | |||
56 | /// <summary> |
||
57 | /// Main back conversion routine - converts PathGeometry object to its string equivalent |
||
58 | /// </summary> |
||
59 | /// <param name="geometry">Path Geometry object</param> |
||
60 | /// <returns>String equivalent to PathGeometry contents</returns> |
||
61 | public string ConvertBack(PathGeometry geometry) |
||
62 | { |
||
63 | if (null == geometry) |
||
64 | throw new ArgumentException("Path Geometry cannot be null!"); |
||
65 | |||
66 | return parseBack(geometry); |
||
67 | } |
||
68 | #endregion |
||
69 | |||
70 | #region Private Functionality |
||
71 | /// <summary> |
||
72 | /// Main parser routine, which loops over each char in received string, and performs actions according to command/parameter being passed |
||
73 | /// </summary> |
||
74 | /// <param name="path">String with path data definition</param> |
||
75 | /// <returns>PathGeometry object created from string definition</returns> |
||
76 | private PathGeometry parse(string path) |
||
77 | { |
||
78 | PathGeometry _pathGeometry = null; |
||
79 | |||
80 | |||
81 | _formatProvider = CultureInfo.InvariantCulture; |
||
82 | _pathString = path; |
||
83 | _pathLength = path.Length; |
||
84 | _curIndex = 0; |
||
85 | |||
86 | _secondLastPoint = new Point(0, 0); |
||
87 | _lastPoint = new Point(0, 0); |
||
88 | _lastStart = new Point(0, 0); |
||
89 | |||
90 | _figureStarted = false; |
||
91 | |||
92 | bool first = true; |
||
93 | |||
94 | char last_cmd = ' '; |
||
95 | |||
96 | while (ReadToken()) // Empty path is allowed in XAML |
||
97 | { |
||
98 | char cmd = _token; |
||
99 | |||
100 | if (first) |
||
101 | { |
||
102 | if ((cmd != 'M') && (cmd != 'm')) // Path starts with M|m |
||
103 | { |
||
104 | ThrowBadToken(); |
||
105 | } |
||
106 | |||
107 | first = false; |
||
108 | } |
||
109 | |||
110 | switch (cmd) |
||
111 | { |
||
112 | case 'm': |
||
113 | case 'M': |
||
114 | // XAML allows multiple points after M/m |
||
115 | _lastPoint = ReadPoint(cmd, !AllowComma); |
||
116 | |||
117 | _figure = new PathFigure(); |
||
118 | _figure.StartPoint = _lastPoint; |
||
119 | _figure.IsFilled = IsFilled; |
||
120 | _figure.IsClosed = !IsClosed; |
||
121 | //context.BeginFigure(_lastPoint, IsFilled, !IsClosed); |
||
122 | _figureStarted = true; |
||
123 | _lastStart = _lastPoint; |
||
124 | last_cmd = 'M'; |
||
125 | |||
126 | while (IsNumber(AllowComma)) |
||
127 | { |
||
128 | _lastPoint = ReadPoint(cmd, !AllowComma); |
||
129 | |||
130 | LineSegment _lineSegment = new LineSegment(); |
||
131 | _lineSegment.Point = _lastPoint; |
||
132 | _figure.Segments.Add(_lineSegment); |
||
133 | //context.LineTo(_lastPoint, IsStroked, !IsSmoothJoin); |
||
134 | last_cmd = 'L'; |
||
135 | } |
||
136 | break; |
||
137 | |||
138 | case 'l': |
||
139 | case 'L': |
||
140 | case 'h': |
||
141 | case 'H': |
||
142 | case 'v': |
||
143 | case 'V': |
||
144 | EnsureFigure(); |
||
145 | |||
146 | do |
||
147 | { |
||
148 | switch (cmd) |
||
149 | { |
||
150 | case 'l': _lastPoint = ReadPoint(cmd, !AllowComma); break; |
||
151 | case 'L': _lastPoint = ReadPoint(cmd, !AllowComma); break; |
||
152 | case 'h': _lastPoint.X += ReadNumber(!AllowComma); break; |
||
153 | case 'H': _lastPoint.X = ReadNumber(!AllowComma); break; |
||
154 | case 'v': _lastPoint.Y += ReadNumber(!AllowComma); break; |
||
155 | case 'V': _lastPoint.Y = ReadNumber(!AllowComma); break; |
||
156 | } |
||
157 | |||
158 | LineSegment _lineSegment = new LineSegment(); |
||
159 | _lineSegment.Point = _lastPoint; |
||
160 | _figure.Segments.Add(_lineSegment); |
||
161 | //context.LineTo(_lastPoint, IsStroked, !IsSmoothJoin); |
||
162 | } |
||
163 | while (IsNumber(AllowComma)); |
||
164 | |||
165 | last_cmd = 'L'; |
||
166 | break; |
||
167 | |||
168 | case 'c': |
||
169 | case 'C': // cubic Bezier |
||
170 | case 's': |
||
171 | case 'S': // smooth cublic Bezier |
||
172 | EnsureFigure(); |
||
173 | |||
174 | do |
||
175 | { |
||
176 | Point p; |
||
177 | |||
178 | if ((cmd == 's') || (cmd == 'S')) |
||
179 | { |
||
180 | if (last_cmd == 'C') |
||
181 | { |
||
182 | p = Reflect(); |
||
183 | } |
||
184 | else |
||
185 | { |
||
186 | p = _lastPoint; |
||
187 | } |
||
188 | |||
189 | _secondLastPoint = ReadPoint(cmd, !AllowComma); |
||
190 | } |
||
191 | else |
||
192 | { |
||
193 | p = ReadPoint(cmd, !AllowComma); |
||
194 | |||
195 | _secondLastPoint = ReadPoint(cmd, AllowComma); |
||
196 | } |
||
197 | |||
198 | _lastPoint = ReadPoint(cmd, AllowComma); |
||
199 | |||
200 | BezierSegment _bizierSegment = new BezierSegment(); |
||
201 | _bizierSegment.Point1 = p; |
||
202 | _bizierSegment.Point2 = _secondLastPoint; |
||
203 | _bizierSegment.Point3 = _lastPoint; |
||
204 | _figure.Segments.Add(_bizierSegment); |
||
205 | //context.BezierTo(p, _secondLastPoint, _lastPoint, IsStroked, !IsSmoothJoin); |
||
206 | |||
207 | last_cmd = 'C'; |
||
208 | } |
||
209 | while (IsNumber(AllowComma)); |
||
210 | |||
211 | break; |
||
212 | |||
213 | case 'q': |
||
214 | case 'Q': // quadratic Bezier |
||
215 | case 't': |
||
216 | case 'T': // smooth quadratic Bezier |
||
217 | EnsureFigure(); |
||
218 | |||
219 | do |
||
220 | { |
||
221 | if ((cmd == 't') || (cmd == 'T')) |
||
222 | { |
||
223 | if (last_cmd == 'Q') |
||
224 | { |
||
225 | _secondLastPoint = Reflect(); |
||
226 | } |
||
227 | else |
||
228 | { |
||
229 | _secondLastPoint = _lastPoint; |
||
230 | } |
||
231 | |||
232 | _lastPoint = ReadPoint(cmd, !AllowComma); |
||
233 | } |
||
234 | else |
||
235 | { |
||
236 | _secondLastPoint = ReadPoint(cmd, !AllowComma); |
||
237 | _lastPoint = ReadPoint(cmd, AllowComma); |
||
238 | } |
||
239 | |||
240 | QuadraticBezierSegment _quadraticBezierSegment = new QuadraticBezierSegment(); |
||
241 | _quadraticBezierSegment.Point1 = _secondLastPoint; |
||
242 | _quadraticBezierSegment.Point2 = _lastPoint; |
||
243 | _figure.Segments.Add(_quadraticBezierSegment); |
||
244 | //context.QuadraticBezierTo(_secondLastPoint, _lastPoint, IsStroked, !IsSmoothJoin); |
||
245 | |||
246 | last_cmd = 'Q'; |
||
247 | } |
||
248 | while (IsNumber(AllowComma)); |
||
249 | |||
250 | break; |
||
251 | |||
252 | case 'a': |
||
253 | case 'A': |
||
254 | EnsureFigure(); |
||
255 | |||
256 | do |
||
257 | { |
||
258 | // A 3,4 5, 0, 0, 6,7 |
||
259 | double w = ReadNumber(!AllowComma); |
||
260 | double h = ReadNumber(AllowComma); |
||
261 | double rotation = ReadNumber(AllowComma); |
||
262 | bool large = ReadBool(); |
||
263 | bool sweep = ReadBool(); |
||
264 | |||
265 | _lastPoint = ReadPoint(cmd, AllowComma); |
||
266 | |||
267 | ArcSegment _arcSegment = new ArcSegment(); |
||
268 | _arcSegment.Point = _lastPoint; |
||
269 | _arcSegment.Size = new Size(w, h); |
||
270 | _arcSegment.RotationAngle = rotation; |
||
271 | _arcSegment.IsLargeArc = large; |
||
272 | _arcSegment.SweepDirection = sweep ? SweepDirection.Clockwise : SweepDirection.Counterclockwise; |
||
273 | _figure.Segments.Add(_arcSegment); |
||
274 | //context.ArcTo( |
||
275 | // _lastPoint, |
||
276 | // new Size(w, h), |
||
277 | // rotation, |
||
278 | // large, |
||
279 | // sweep ? SweepDirection.Clockwise : SweepDirection.Counterclockwise, |
||
280 | // IsStroked, |
||
281 | // !IsSmoothJoin |
||
282 | // ); |
||
283 | } |
||
284 | while (IsNumber(AllowComma)); |
||
285 | |||
286 | last_cmd = 'A'; |
||
287 | break; |
||
288 | |||
289 | case 'z': |
||
290 | case 'Z': |
||
291 | EnsureFigure(); |
||
292 | _figure.IsClosed = IsClosed; |
||
293 | //context.SetClosedState(IsClosed); |
||
294 | |||
295 | _figureStarted = false; |
||
296 | last_cmd = 'Z'; |
||
297 | |||
298 | _lastPoint = _lastStart; // Set reference point to be first point of current figure |
||
299 | break; |
||
300 | |||
301 | default: |
||
302 | ThrowBadToken(); |
||
303 | break; |
||
304 | } |
||
305 | } |
||
306 | |||
307 | if (null != _figure) |
||
308 | { |
||
309 | _pathGeometry = new PathGeometry(); |
||
310 | _pathGeometry.Figures.Add(_figure); |
||
311 | |||
312 | } |
||
313 | return _pathGeometry; |
||
314 | } |
||
315 | |||
316 | void SkipDigits(bool signAllowed) |
||
317 | { |
||
318 | // Allow for a sign |
||
319 | if (signAllowed && More() && ((_pathString[_curIndex] == '-') || _pathString[_curIndex] == '+')) |
||
320 | { |
||
321 | _curIndex++; |
||
322 | } |
||
323 | |||
324 | while (More() && (_pathString[_curIndex] >= '0') && (_pathString[_curIndex] <= '9')) |
||
325 | { |
||
326 | _curIndex++; |
||
327 | } |
||
328 | } |
||
329 | |||
330 | bool ReadBool() |
||
331 | { |
||
332 | SkipWhiteSpace(AllowComma); |
||
333 | |||
334 | if (More()) |
||
335 | { |
||
336 | _token = _pathString[_curIndex++]; |
||
337 | |||
338 | if (_token == '0') |
||
339 | { |
||
340 | return false; |
||
341 | } |
||
342 | else if (_token == '1') |
||
343 | { |
||
344 | return true; |
||
345 | } |
||
346 | } |
||
347 | |||
348 | ThrowBadToken(); |
||
349 | |||
350 | return false; |
||
351 | } |
||
352 | |||
353 | private Point Reflect() |
||
354 | { |
||
355 | return new Point(2 * _lastPoint.X - _secondLastPoint.X, |
||
356 | 2 * _lastPoint.Y - _secondLastPoint.Y); |
||
357 | } |
||
358 | |||
359 | private void EnsureFigure() |
||
360 | { |
||
361 | if (!_figureStarted) |
||
362 | { |
||
363 | _figure = new PathFigure(); |
||
364 | _figure.StartPoint = _lastStart; |
||
365 | |||
366 | //_context.BeginFigure(_lastStart, IsFilled, !IsClosed); |
||
367 | _figureStarted = true; |
||
368 | } |
||
369 | } |
||
370 | |||
371 | double ReadNumber(bool allowComma) |
||
372 | { |
||
373 | if (!IsNumber(allowComma)) |
||
374 | { |
||
375 | ThrowBadToken(); |
||
376 | } |
||
377 | |||
378 | bool simple = true; |
||
379 | int start = _curIndex; |
||
380 | |||
381 | // |
||
382 | // Allow for a sign |
||
383 | // |
||
384 | // There are numbers that cannot be preceded with a sign, for instance, -NaN, but it's |
||
385 | // fine to ignore that at this point, since the CLR parser will catch this later. |
||
386 | // |
||
387 | if (More() && ((_pathString[_curIndex] == '-') || _pathString[_curIndex] == '+')) |
||
388 | { |
||
389 | _curIndex++; |
||
390 | } |
||
391 | |||
392 | // Check for Infinity (or -Infinity). |
||
393 | if (More() && (_pathString[_curIndex] == 'I')) |
||
394 | { |
||
395 | // |
||
396 | // Don't bother reading the characters, as the CLR parser will |
||
397 | // do this for us later. |
||
398 | // |
||
399 | _curIndex = Math.Min(_curIndex + 8, _pathLength); // "Infinity" has 8 characters |
||
400 | simple = false; |
||
401 | } |
||
402 | // Check for NaN |
||
403 | else if (More() && (_pathString[_curIndex] == 'N')) |
||
404 | { |
||
405 | // |
||
406 | // Don't bother reading the characters, as the CLR parser will |
||
407 | // do this for us later. |
||
408 | // |
||
409 | _curIndex = Math.Min(_curIndex + 3, _pathLength); // "NaN" has 3 characters |
||
410 | simple = false; |
||
411 | } |
||
412 | else |
||
413 | { |
||
414 | SkipDigits(!AllowSign); |
||
415 | |||
416 | // Optional period, followed by more digits |
||
417 | if (More() && (_pathString[_curIndex] == '.')) |
||
418 | { |
||
419 | simple = false; |
||
420 | _curIndex++; |
||
421 | SkipDigits(!AllowSign); |
||
422 | } |
||
423 | |||
424 | // Exponent |
||
425 | if (More() && ((_pathString[_curIndex] == 'E') || (_pathString[_curIndex] == 'e'))) |
||
426 | { |
||
427 | simple = false; |
||
428 | _curIndex++; |
||
429 | SkipDigits(AllowSign); |
||
430 | } |
||
431 | } |
||
432 | |||
433 | if (simple && (_curIndex <= (start + 8))) // 32-bit integer |
||
434 | { |
||
435 | int sign = 1; |
||
436 | |||
437 | if (_pathString[start] == '+') |
||
438 | { |
||
439 | start++; |
||
440 | } |
||
441 | else if (_pathString[start] == '-') |
||
442 | { |
||
443 | start++; |
||
444 | sign = -1; |
||
445 | } |
||
446 | |||
447 | int value = 0; |
||
448 | |||
449 | while (start < _curIndex) |
||
450 | { |
||
451 | value = value * 10 + (_pathString[start] - '0'); |
||
452 | start++; |
||
453 | } |
||
454 | |||
455 | return value * sign; |
||
456 | } |
||
457 | else |
||
458 | { |
||
459 | string subString = _pathString.Substring(start, _curIndex - start); |
||
460 | |||
461 | try |
||
462 | { |
||
463 | return System.Convert.ToDouble(subString, _formatProvider); |
||
464 | } |
||
465 | catch (FormatException except) |
||
466 | { |
||
467 | throw new FormatException(string.Format("Unexpected character in path '{0}' at position {1}", _pathString, _curIndex - 1), except); |
||
468 | } |
||
469 | } |
||
470 | } |
||
471 | |||
472 | private bool IsNumber(bool allowComma) |
||
473 | { |
||
474 | bool commaMet = SkipWhiteSpace(allowComma); |
||
475 | |||
476 | if (More()) |
||
477 | { |
||
478 | _token = _pathString[_curIndex]; |
||
479 | |||
480 | // Valid start of a number |
||
481 | if ((_token == '.') || (_token == '-') || (_token == '+') || ((_token >= '0') && (_token <= '9')) |
||
482 | || (_token == 'I') // Infinity |
||
483 | || (_token == 'N')) // NaN |
||
484 | { |
||
485 | return true; |
||
486 | } |
||
487 | } |
||
488 | |||
489 | if (commaMet) // Only allowed between numbers |
||
490 | { |
||
491 | ThrowBadToken(); |
||
492 | } |
||
493 | |||
494 | return false; |
||
495 | } |
||
496 | |||
497 | private Point ReadPoint(char cmd, bool allowcomma) |
||
498 | { |
||
499 | double x = ReadNumber(allowcomma); |
||
500 | double y = ReadNumber(AllowComma); |
||
501 | |||
502 | if (cmd >= 'a') // 'A' < 'a'. lower case for relative |
||
503 | { |
||
504 | x += _lastPoint.X; |
||
505 | y += _lastPoint.Y; |
||
506 | } |
||
507 | |||
508 | return new Point(x, y); |
||
509 | } |
||
510 | |||
511 | private bool ReadToken() |
||
512 | { |
||
513 | SkipWhiteSpace(!AllowComma); |
||
514 | |||
515 | // Check for end of string |
||
516 | if (More()) |
||
517 | { |
||
518 | _token = _pathString[_curIndex++]; |
||
519 | |||
520 | return true; |
||
521 | } |
||
522 | else |
||
523 | { |
||
524 | return false; |
||
525 | } |
||
526 | } |
||
527 | |||
528 | bool More() |
||
529 | { |
||
530 | return _curIndex < _pathLength; |
||
531 | } |
||
532 | |||
533 | // Skip white space, one comma if allowed |
||
534 | private bool SkipWhiteSpace(bool allowComma) |
||
535 | { |
||
536 | bool commaMet = false; |
||
537 | |||
538 | while (More()) |
||
539 | { |
||
540 | char ch = _pathString[_curIndex]; |
||
541 | |||
542 | switch (ch) |
||
543 | { |
||
544 | case ' ': |
||
545 | case '\n': |
||
546 | case '\r': |
||
547 | case '\t': // SVG whitespace |
||
548 | break; |
||
549 | f1918134 | djkim | case ';': |
550 | 787a4489 | KangIngu | case ',': |
551 | if (allowComma) |
||
552 | { |
||
553 | commaMet = true; |
||
554 | allowComma = false; // one comma only |
||
555 | } |
||
556 | else |
||
557 | { |
||
558 | ThrowBadToken(); |
||
559 | } |
||
560 | break; |
||
561 | |||
562 | default: |
||
563 | // Avoid calling IsWhiteSpace for ch in (' ' .. 'z'] |
||
564 | if (((ch > ' ') && (ch <= 'z')) || !Char.IsWhiteSpace(ch)) |
||
565 | { |
||
566 | return commaMet; |
||
567 | } |
||
568 | break; |
||
569 | } |
||
570 | |||
571 | _curIndex++; |
||
572 | } |
||
573 | |||
574 | return commaMet; |
||
575 | } |
||
576 | |||
577 | private void ThrowBadToken() |
||
578 | { |
||
579 | throw new FormatException(string.Format("Unexpected character in path '{0}' at position {1}", _pathString, _curIndex - 1)); |
||
580 | } |
||
581 | |||
582 | static internal char GetNumericListSeparator(IFormatProvider provider) |
||
583 | { |
||
584 | char numericSeparator = ','; |
||
585 | |||
586 | // Get the NumberFormatInfo out of the provider, if possible |
||
587 | // If the IFormatProvider doesn't not contain a NumberFormatInfo, then |
||
588 | // this method returns the current culture's NumberFormatInfo. |
||
589 | NumberFormatInfo numberFormat = NumberFormatInfo.GetInstance(provider); |
||
590 | |||
591 | // Is the decimal separator is the same as the list separator? |
||
592 | // If so, we use the ";". |
||
593 | if ((numberFormat.NumberDecimalSeparator.Length > 0) && (numericSeparator == numberFormat.NumberDecimalSeparator[0])) |
||
594 | { |
||
595 | numericSeparator = ';'; |
||
596 | } |
||
597 | |||
598 | return numericSeparator; |
||
599 | } |
||
600 | |||
601 | private string parseBack(PathGeometry geometry) |
||
602 | { |
||
603 | System.Text.StringBuilder sb = new System.Text.StringBuilder(); |
||
604 | IFormatProvider provider = new System.Globalization.CultureInfo("en-us"); |
||
605 | string format = null; |
||
606 | |||
607 | foreach (PathFigure figure in geometry.Figures) |
||
608 | { |
||
609 | sb.Append("M " + ((IFormattable)figure.StartPoint).ToString(format, provider) + " "); |
||
610 | |||
611 | foreach (PathSegment segment in figure.Segments) |
||
612 | { |
||
613 | char separator = GetNumericListSeparator(provider); |
||
614 | |||
615 | if (segment.GetType() == typeof(LineSegment)) |
||
616 | { |
||
617 | LineSegment _lineSegment = segment as LineSegment; |
||
618 | |||
619 | sb.Append("L " + ((IFormattable)_lineSegment.Point).ToString(format, provider) + " "); |
||
620 | } |
||
621 | else if (segment.GetType() == typeof(BezierSegment)) |
||
622 | { |
||
623 | BezierSegment _bezierSegment = segment as BezierSegment; |
||
624 | |||
625 | sb.Append(String.Format(provider, |
||
626 | "C{1:" + format + "}{0}{2:" + format + "}{0}{3:" + format + "} ", |
||
627 | separator, |
||
628 | _bezierSegment.Point1, |
||
629 | _bezierSegment.Point2, |
||
630 | _bezierSegment.Point3 |
||
631 | )); |
||
632 | } |
||
633 | else if (segment.GetType() == typeof(QuadraticBezierSegment)) |
||
634 | { |
||
635 | QuadraticBezierSegment _quadraticBezierSegment = segment as QuadraticBezierSegment; |
||
636 | |||
637 | sb.Append(String.Format(provider, |
||
638 | "Q{1:" + format + "}{0}{2:" + format + "} ", |
||
639 | separator, |
||
640 | _quadraticBezierSegment.Point1, |
||
641 | _quadraticBezierSegment.Point2)); |
||
642 | } |
||
643 | else if (segment.GetType() == typeof(ArcSegment)) |
||
644 | { |
||
645 | ArcSegment _arcSegment = segment as ArcSegment; |
||
646 | |||
647 | sb.Append(String.Format(provider, |
||
648 | "A{1:" + format + "}{0}{2:" + format + "}{0}{3}{0}{4}{0}{5:" + format + "} ", |
||
649 | separator, |
||
650 | _arcSegment.Size, |
||
651 | _arcSegment.RotationAngle, |
||
652 | _arcSegment.IsLargeArc ? "1" : "0", |
||
653 | _arcSegment.SweepDirection == SweepDirection.Clockwise ? "1" : "0", |
||
654 | _arcSegment.Point)); |
||
655 | } |
||
656 | } |
||
657 | |||
658 | if (figure.IsClosed) |
||
659 | sb.Append("Z"); |
||
660 | } |
||
661 | |||
662 | return sb.ToString(); |
||
663 | } |
||
664 | #endregion |
||
665 | |||
666 | #region IValueConverter Members |
||
667 | |||
668 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) |
||
669 | { |
||
670 | string path = value as string; |
||
671 | if (null != path) |
||
672 | return Convert(path); |
||
673 | else |
||
674 | return null; |
||
675 | } |
||
676 | |||
677 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) |
||
678 | { |
||
679 | PathGeometry geometry = value as PathGeometry; |
||
680 | |||
681 | if (null != geometry) |
||
682 | return ConvertBack(geometry); |
||
683 | else |
||
684 | return default(string); |
||
685 | } |
||
686 | |||
687 | #endregion |
||
688 | |||
689 | public void Dispose() |
||
690 | { |
||
691 | a6f7f9b6 | djkim | //GC.Collect(); |
692 | 24c5e56c | taeseongkim | ////GC.SuppressFinalize(this); |
693 | 787a4489 | KangIngu | } |
694 | } |
||
695 | } |