Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GrammaticalOptimization/SharpVectorModel/Paths/SvgPathSegList.cs @ 12829

Last change on this file since 12829 was 12762, checked in by aballeit, 9 years ago

#2283 GUI updates, Tree-chart, MCTS Version 2 (prune leaves)

File size: 18.4 KB
Line 
1using System;
2using System.Text;
3using System.Collections.Generic;
4using System.Text.RegularExpressions;
5
6namespace SharpVectors.Dom.Svg
7{
8    // TODO: should we check that the list starts with a M/m since that's required by the spec?
9    public class SvgPathSegList : ISvgPathSegList
10    {
11        #region Private Fields
12
13        private string _pathScript;
14        private bool readOnly;
15        private List<ISvgPathSeg> segments = new List<ISvgPathSeg>();
16
17        private static Regex rePathCmd = new Regex(@"(?=[A-DF-Za-df-z])");
18        private static Regex coordSplit = new Regex(@"(\s*,\s*)|(\s+)|((?<=[0-9])(?=-))", RegexOptions.ExplicitCapture);
19
20        #endregion
21
22        #region Constructors
23
24        public SvgPathSegList(string d, bool readOnly)
25        {
26            if (d == null)
27            {
28                d = String.Empty;
29            }
30
31            _pathScript = d;
32           
33            if (!String.IsNullOrEmpty(d))
34            {
35                ParseString(d);
36            }
37
38            this.readOnly = readOnly;
39        }
40
41        #endregion
42
43        #region Public Properties
44
45        public string PathScript
46        {
47            get
48            {
49                return _pathScript;
50            }
51        }
52
53        #endregion
54
55        #region Private Methods
56
57        private void ParseString(string d)
58        {
59            ISvgPathSeg seg;
60            string[] segs = rePathCmd.Split(d);
61
62            foreach (string s in segs)
63            {
64                string segment = s.Trim();
65                if (segment.Length > 0)
66                {
67                    char cmd = (char)segment.ToCharArray(0, 1)[0];
68                    double[] coords = getCoords(segment);
69                    int length = coords.Length;
70                    switch (cmd)
71                    {
72                        #region moveto
73                        case 'M':
74                            for (int i = 0; i < length; i += 2)
75                            {
76                                if (i == 0)
77                                {
78                                    seg = new SvgPathSegMovetoAbs(coords[i], coords[i + 1]);
79                                }
80                                else
81                                {
82                                    seg = new SvgPathSegLinetoAbs(coords[i], coords[i + 1]);
83                                }
84                                AppendItem(seg);
85                            }
86                            break;
87                        case 'm':
88                            for (int i = 0; i < length; i += 2)
89                            {
90                                if (i == 0)
91                                {
92                                    seg = new SvgPathSegMovetoRel(coords[i], coords[i + 1]);
93                                }
94                                else
95                                {
96                                    seg = new SvgPathSegLinetoRel(coords[i], coords[i + 1]);
97                                }
98                                AppendItem(seg);
99                            }
100                            break;
101                        #endregion
102                        #region lineto
103                        case 'L':
104                            for (int i = 0; i < length; i += 2)
105                            {
106                                seg = new SvgPathSegLinetoAbs(coords[i], coords[i + 1]);
107                                AppendItem(seg);
108                            }
109                            break;
110                        case 'l':
111                            for (int i = 0; i < length; i += 2)
112                            {
113                                seg = new SvgPathSegLinetoRel(coords[i], coords[i + 1]);
114                                AppendItem(seg);
115                            }
116                            break;
117                        case 'H':
118                            for (int i = 0; i < length; i++)
119                            {
120                                seg = new SvgPathSegLinetoHorizontalAbs(coords[i]);
121                                AppendItem(seg);
122                            }
123                            break;
124                        case 'h':
125                            for (int i = 0; i < length; i++)
126                            {
127                                seg = new SvgPathSegLinetoHorizontalRel(coords[i]);
128                                AppendItem(seg);
129                            }
130                            break;
131                        case 'V':
132                            for (int i = 0; i < length; i++)
133                            {
134                                seg = new SvgPathSegLinetoVerticalAbs(coords[i]);
135                                AppendItem(seg);
136                            }
137                            break;
138                        case 'v':
139                            for (int i = 0; i < length; i++)
140                            {
141                                seg = new SvgPathSegLinetoVerticalRel(coords[i]);
142                                AppendItem(seg);
143                            }
144                            break;
145                        #endregion
146                        #region beziers
147                        case 'C':
148                            for (int i = 0; i < length; i += 6)
149                            {
150                                seg = new SvgPathSegCurvetoCubicAbs(
151                                    coords[i + 4],
152                                    coords[i + 5],
153                                    coords[i],
154                                    coords[i + 1],
155                                    coords[i + 2],
156                                    coords[i + 3]);
157                                AppendItem(seg);
158                            }
159                            break;
160                        case 'c':
161                            for (int i = 0; i < length; i += 6)
162                            {
163                                seg = new SvgPathSegCurvetoCubicRel(
164                                    coords[i + 4],
165                                    coords[i + 5],
166                                    coords[i],
167                                    coords[i + 1],
168                                    coords[i + 2],
169                                    coords[i + 3]);
170
171                                AppendItem(seg);
172                            }
173                            break;
174                        case 'S':
175                            for (int i = 0; i < length; i += 4)
176                            {
177                                seg = new SvgPathSegCurvetoCubicSmoothAbs(
178                                    coords[i + 2],
179                                    coords[i + 3],
180                                    coords[i],
181                                    coords[i + 1]);
182                                AppendItem(seg);
183                            }
184                            break;
185                        case 's':
186                            for (int i = 0; i < length; i += 4)
187                            {
188                                seg = new SvgPathSegCurvetoCubicSmoothRel(
189                                    coords[i + 2],
190                                    coords[i + 3],
191                                    coords[i],
192                                    coords[i + 1]);
193                                AppendItem(seg);
194                            }
195                            break;
196                        case 'Q':
197                            for (int i = 0; i < length; i += 4)
198                            {
199                                seg = new SvgPathSegCurvetoQuadraticAbs(
200                                    coords[i + 2],
201                                    coords[i + 3],
202                                    coords[i],
203                                    coords[i + 1]);
204                                AppendItem(seg);
205                            }
206                            break;
207                        case 'q':
208                            for (int i = 0; i < length; i += 4)
209                            {
210                                seg = new SvgPathSegCurvetoQuadraticRel(
211                                    coords[i + 2],
212                                    coords[i + 3],
213                                    coords[i],
214                                    coords[i + 1]);
215                                AppendItem(seg);
216                            }
217                            break;
218                        case 'T':
219                            for (int i = 0; i < length; i += 2)
220                            {
221                                seg = new SvgPathSegCurvetoQuadraticSmoothAbs(
222                                    coords[i], coords[i + 1]);
223                                AppendItem(seg);
224                            }
225                            break;
226                        case 't':
227                            for (int i = 0; i < length; i += 2)
228                            {
229                                seg = new SvgPathSegCurvetoQuadraticSmoothRel(
230                                    coords[i], coords[i + 1]);
231                                AppendItem(seg);
232                            }
233                            break;
234                        #endregion
235                        #region arcs
236                        case 'A':
237                        case 'a':
238                            for (int i = 0; i < length; i += 7)
239                            {
240                                if (cmd == 'A')
241                                {
242                                    seg = new SvgPathSegArcAbs(
243                                        coords[i + 5],
244                                        coords[i + 6],
245                                        coords[i],
246                                        coords[i + 1],
247                                        coords[i + 2],
248                                        (coords[i + 3] != 0),
249                                        (coords[i + 4] != 0));
250                                }
251                                else
252                                {
253                                    seg = new SvgPathSegArcRel(
254                                        coords[i + 5],
255                                        coords[i + 6],
256                                        coords[i],
257                                        coords[i + 1],
258                                        coords[i + 2],
259                                        (coords[i + 3] != 0),
260                                        (coords[i + 4] != 0));
261                                }
262                                AppendItem(seg);
263                            }
264                            break;
265                        #endregion
266                        #region close
267                        case 'z':
268                        case 'Z':
269                            seg = new SvgPathSegClosePath();
270                            AppendItem(seg);
271                            break;
272                        #endregion
273                        #region Unknown path command
274                        default:
275                            throw new ApplicationException(String.Format("Unknown path command - ({0})", cmd));
276                        #endregion
277                    }
278                }
279            }
280        }
281
282        private double[] getCoords(String segment)
283        {
284            double[] coords = new double[0];
285
286            segment = segment.Substring(1);
287            segment = segment.Trim();
288            segment = segment.Trim(new char[] { ',' });
289
290            if (segment.Length > 0)
291            {
292                string[] sCoords = coordSplit.Split(segment);
293
294                coords = new double[sCoords.Length];
295                for (int i = 0; i < sCoords.Length; i++)
296                {
297                    coords[i] = SvgNumber.ParseNumber(sCoords[i]);
298                }
299            }
300            return coords;
301        }
302
303        private void setListAndIndex(SvgPathSeg newItem, int index)
304        {
305            if (newItem != null)
306            {
307                newItem.SetList(this);
308                newItem.SetIndex(index);
309            }
310            else
311            {
312                throw new SvgException(SvgExceptionType.SvgWrongTypeErr,
313                    "Can only add SvgPathSeg subclasses to ISvgPathSegList");
314            }
315        }
316
317        private void changeIndexes(int startAt, int diff)
318        {
319            int count = segments.Count;
320            for (int i = startAt; i < count; i++)
321            {
322                SvgPathSeg seg = segments[i] as SvgPathSeg;
323                if (seg != null)
324                {
325                    seg.SetIndexWithDiff(diff);
326                }
327            }
328        }
329        #endregion
330
331        #region ISvgPathSegList Members
332
333        public int NumberOfItems
334        {
335            get
336            {
337                return segments.Count;
338            }
339        }
340
341        public void Clear()
342        {
343            if (readOnly)
344            {
345                throw new DomException(DomExceptionType.NoModificationAllowedErr);
346            }
347            else
348            {
349                segments.Clear();
350            }
351        }
352
353        public ISvgPathSeg Initialize(ISvgPathSeg newItem)
354        {
355            Clear();
356
357            return AppendItem(newItem);
358        }
359
360        public ISvgPathSeg GetItem(int index)
361        {
362            if (index < 0 || index >= NumberOfItems)
363            {
364                throw new DomException(DomExceptionType.IndexSizeErr);
365            }
366
367            return segments[index];
368        }
369        public ISvgPathSeg this[int index]
370        {
371            get
372            {
373                return GetItem(index);
374            }
375            set
376            {
377                ReplaceItem(value, index);
378            }
379        }
380
381        public ISvgPathSeg InsertItemBefore(ISvgPathSeg newItem, int index)
382        {
383            if (readOnly)
384            {
385                throw new DomException(DomExceptionType.NoModificationAllowedErr);
386            }
387            else
388            {
389                segments.Insert(index, newItem);
390                setListAndIndex(newItem as SvgPathSeg, index);
391                changeIndexes(index + 1, 1);
392
393                return newItem;
394            }
395        }
396
397        public ISvgPathSeg ReplaceItem(ISvgPathSeg newItem, int index)
398        {
399            if (readOnly)
400            {
401                throw new DomException(DomExceptionType.NoModificationAllowedErr);
402            }
403            else
404            {
405                ISvgPathSeg replacedItem = GetItem(index);
406                segments[index] = newItem;
407                setListAndIndex(newItem as SvgPathSeg, index);
408
409                return replacedItem;
410            }
411        }
412
413        public ISvgPathSeg RemoveItem(int index)
414        {
415            if (readOnly)
416            {
417                throw new DomException(DomExceptionType.NoModificationAllowedErr);
418            }
419            else
420            {
421                ISvgPathSeg result = GetItem(index);
422                segments.RemoveAt(index);
423                changeIndexes(index, -1);
424
425                return result;
426            }
427        }
428
429        public ISvgPathSeg AppendItem(ISvgPathSeg newItem)
430        {
431            if (readOnly)
432            {
433                throw new DomException(DomExceptionType.NoModificationAllowedErr);
434            }
435            else
436            {
437                segments.Add(newItem);
438                setListAndIndex(newItem as SvgPathSeg, segments.Count - 1);
439
440                return newItem;
441            }
442        }
443
444        #endregion
445
446        #region Public members
447
448        public SvgPointF[] Points
449        {
450            get
451            {
452                List<SvgPointF> ret = new List<SvgPointF>();
453                foreach (SvgPathSeg seg in segments)
454                {
455                    ret.Add(seg.AbsXY);
456                }
457
458                return ret.ToArray();
459            }
460        }
461
462        internal SvgPathSeg GetPreviousSegment(SvgPathSeg seg)
463        {
464            int index = segments.IndexOf(seg);
465            if (index == -1)
466            {
467                throw new Exception("Path segment not part of this list");
468            }
469            else if (index == 0)
470            {
471                return null;
472            }
473            else
474            {
475                return (SvgPathSeg)GetItem(index - 1);
476            }
477        }
478
479        internal SvgPathSeg GetNextSegment(SvgPathSeg seg)
480        {
481            int index = segments.IndexOf(seg);
482            if (index == -1)
483            {
484                throw new Exception("Path segment not part of this list");
485            }
486            else if (index == segments.Count - 1)
487            {
488                return null;
489            }
490            else
491            {
492                return (SvgPathSeg)this[index + 1];
493            }
494        }
495
496        public double GetStartAngle(int index)
497        {
498            return ((SvgPathSeg)this[index]).StartAngle;
499        }
500
501        public double GetEndAngle(int index)
502        {
503            return ((SvgPathSeg)this[index]).EndAngle;
504        }
505
506        public string PathText
507        {
508            get
509            {
510                StringBuilder sb = new StringBuilder();
511                foreach (SvgPathSeg seg in segments)
512                {
513                    sb.Append(seg.PathText);
514                }
515                return sb.ToString();
516            }
517        }
518
519        internal double GetTotalLength()
520        {
521            double result = 0;
522            foreach (SvgPathSeg segment in segments)
523            {
524                result += segment.Length;
525            }
526            return result;
527        }
528
529        internal int GetPathSegAtLength(double distance)
530        {
531            double result = 0;
532            foreach (SvgPathSeg segment in segments)
533            {
534                result += segment.Length;
535                if (result > distance)
536                {
537                    return segment.Index;
538                }
539            }
540            // distance was to big, return last item index
541            // TODO: is this correct?
542            return NumberOfItems - 1;
543        }
544
545        #endregion
546    }
547}
Note: See TracBrowser for help on using the repository browser.