/// <summary>
        /// Initializes the Path Element with the given Match
        /// </summary>
        /// <param name="match">Match object</param>
        /// <param name="index">Index of the path element in the Path data.</param>
        public override void Initialize(Match match, int index)
        {
            Index = index;
            var main = match.Groups["Main"];

            Data = main.Value;

            var elements = new List <ICanvasPathElement>();

            foreach (PathElementType type in Enum.GetValues(typeof(PathElementType)))
            {
                foreach (Capture elementCapture in match.Groups[type.ToString()].Captures)
                {
                    var elementRootIndex = elementCapture.Index;
                    var regex            = RegexFactory.GetRegex(type);
                    var elementMatch     = regex.Match(elementCapture.Value);
                    var isRelative       = false;

                    // Process the 'Main' Group which contains the Path Command and
                    // corresponding attributes
                    if (elementMatch.Groups["Main"].Captures.Count == 1)
                    {
                        var figure = PathElementFactory.CreatePathElement(type, elementMatch, elementRootIndex);
                        elements.Add(figure);
                        isRelative = figure.IsRelative;
                    }

                    // Process the 'Additional' Group which contains just the attributes
                    elements.AddRange(from Capture capture in elementMatch.Groups["Additional"].Captures
                                      select PathElementFactory.CreateAdditionalPathElement(type, capture, elementRootIndex + capture.Index, isRelative));
                }
            }

            // Sort the path elements based on their index value
            _elements.AddRange(elements.OrderBy(e => e.Index));
            if (_elements.Count <= 0)
            {
                return;
            }

            // Check if the last path element in the figure is an ClosePathElement
            // which would indicate that the path needs to be closed. Otherwise,
            // add a default ClosePathElement at the end to indicate that the path
            // is not closed.
            var lastElement = _elements.ElementAt(_elements.Count - 1);

            if ((lastElement as ClosePathElement) == null)
            {
                _elements.Add(PathElementFactory.CreateDefaultPathElement(PathElementType.ClosePath));
            }

            // Validation Count will be the cumulative sum of the validation count
            // of child elements of the PathFigure
            ValidationCount = _elements.Sum(x => x.ValidationCount);
        }
Beispiel #2
0
        /// <summary>
        /// Parses the Path data in string format and converts it to CanvasGeometry.
        /// </summary>
        /// <param name="resourceCreator">ICanvasResourceCreator</param>
        /// <param name="pathData">Path data</param>
        /// <param name="logger">(Optional) For logging purpose. To log the set of
        /// CanvasPathBuilder commands, used for creating the CanvasGeometry, in
        /// string format.</param>
        /// <returns>CanvasGeometry</returns>
        public static CanvasGeometry Parse(ICanvasResourceCreator resourceCreator, string pathData,
                                           StringBuilder logger = null)
        {
            var pathFigures = new List <ICanvasPathElement>();

            var matches = RegexFactory.CanvasGeometryRegex.Matches(pathData);

            // If no match is found or no captures in the match, then it means
            // that the path data is invalid.
            if ((matches == null) || (matches.Count == 0))
            {
                throw new ArgumentException($"Invalid Path data!\nPath Data: {pathData}", nameof(pathData));
            }

            // If the match contains more than one captures, it means that there
            // are multiple FillRuleElements present in the path data. There can
            // be only one FillRuleElement in the path data (at the beginning).
            if (matches.Count > 1)
            {
                throw new ArgumentException("Multiple FillRule elements present in Path Data! " +
                                            "There should be only one FillRule within the Path Data. " +
                                            "You can either remove additional FillRule elements or split the Path Data " +
                                            "into multiple Path Data and call the CanvasObject.CreateGeometry() method on each of them." +
                                            $"\nPath Data: {pathData}");
            }

            var figures = new List <ICanvasPathElement>();

            foreach (PathFigureType type in Enum.GetValues(typeof(PathFigureType)))
            {
                foreach (Capture figureCapture in matches[0].Groups[type.ToString()].Captures)
                {
                    var figureRootIndex = figureCapture.Index;
                    var regex           = RegexFactory.GetRegex(type);
                    var figureMatch     = regex.Match(figureCapture.Value);
                    if (!figureMatch.Success)
                    {
                        continue;
                    }
                    // Process the 'Main' Group which contains the Path Command and
                    // corresponding attributes
                    var figure = PathElementFactory.CreatePathFigure(type, figureMatch, figureRootIndex);
                    figures.Add(figure);

                    // Process the 'Additional' Group which contains just the attributes
                    figures.AddRange(from Capture capture in figureMatch.Groups["Additional"].Captures
                                     select PathElementFactory.CreateAdditionalPathFigure(type, capture, figureRootIndex + capture.Index, figure.IsRelative));
                }
            }

            // Sort the figures by their indices
            pathFigures.AddRange(figures.OrderBy(f => f.Index));
            if (pathFigures.Count > 0)
            {
                // Check if the first element in the _figures list is a FillRuleElement
                // which would indicate the fill rule to be followed while creating the
                // path. If it is not present, then insert a default FillRuleElement at
                // the beginning.
                if ((pathFigures.ElementAt(0) as FillRuleElement) == null)
                {
                    pathFigures.Insert(0, PathElementFactory.CreateDefaultPathElement(PathFigureType.FillRule));
                }
            }

            // Perform validation to check if there are any invalid characters in the path data that were not captured
            var preValidationCount = RegexFactory.ValidationRegex.Replace(pathData, string.Empty).Length;

            var postValidationCount = pathFigures.Sum(x => x.ValidationCount);

            if (preValidationCount != postValidationCount)
            {
                throw new ArgumentException($"Path data contains invalid characters!\nPath Data: {pathData}", nameof(pathData));
            }

            if (pathFigures.Count == 0)
            {
                return(null);
            }

            ICanvasPathElement lastElement = null;
            var currentPoint = Vector2.Zero;

            using (var pathBuilder = new CanvasPathBuilder(resourceCreator))
            {
                foreach (var pathFigure in pathFigures)
                {
                    currentPoint = pathFigure.CreatePath(pathBuilder, currentPoint, ref lastElement, logger);
                }

                return(CanvasGeometry.CreatePath(pathBuilder));
            }
        }
        /// <summary>
        /// Parses the Path data in string format and converts it to <see cref="CanvasGeometry"/>.
        /// </summary>
        /// <param name="resourceCreator">ICanvasResourceCreator</param>
        /// <param name="pathData">Path data</param>
        /// <returns><see cref="CanvasGeometry"/></returns>
        internal static CanvasGeometry Parse(ICanvasResourceCreator resourceCreator, string pathData)
        {
            var pathFigures = new List <ICanvasPathElement>();

            var matches = RegexFactory.CanvasGeometryRegex.Matches(pathData);

            // If no match is found or no captures in the match, then it means // that the path data is invalid.
            if (matches.Count == 0)
            {
                ThrowForZeroCount();
            }

            // If the match contains more than one captures, it means that there are multiple FillRuleElements present in the path data.
            // There can be only one FillRuleElement in the path data (at the beginning).
            if (matches.Count > 1)
            {
                ThrowForNotOneCount();
            }

            var figures = new List <ICanvasPathElement>();

            foreach (PathFigureType type in Enum.GetValues(typeof(PathFigureType)))
            {
                foreach (Capture figureCapture in matches[0].Groups[type.ToString()].Captures)
                {
                    var figureRootIndex = figureCapture.Index;
                    var regex           = RegexFactory.GetRegex(type);
                    var figureMatch     = regex.Match(figureCapture.Value);
                    if (!figureMatch.Success)
                    {
                        continue;
                    }

                    // Process the 'Main' Group which contains the Path Command and
                    // corresponding attributes
                    var figure = PathElementFactory.CreatePathFigure(type, figureMatch, figureRootIndex);
                    figures.Add(figure);

                    // Process the 'Additional' Group which contains just the attributes
                    figures.AddRange(from Capture capture in figureMatch.Groups["Additional"].Captures
                                     select PathElementFactory.CreateAdditionalPathFigure(type, capture, figureRootIndex + capture.Index, figure.IsRelative));
                }
            }

            // Sort the figures by their indices
            pathFigures.AddRange(figures.OrderBy(f => f.Index));
            if (pathFigures.Count > 0)
            {
                // Check if the first element in the _figures list is a FillRuleElement
                // which would indicate the fill rule to be followed while creating the
                // path. If it is not present, then insert a default FillRuleElement at
                // the beginning.
                if ((pathFigures.ElementAt(0) as FillRuleElement) == null)
                {
                    pathFigures.Insert(0, PathElementFactory.CreateDefaultPathElement(PathFigureType.FillRule));
                }
            }
            else
            {
                return(null);
            }

            // Perform validation to check if there are any invalid characters in the path data that were not captured
            var preValidationCount  = RegexFactory.ValidationRegex.Replace(pathData, string.Empty).Length;
            var postValidationCount = pathFigures.Sum(x => x.ValidationCount);

            // If there are invalid characters, extract them and add them to the ArgumentException message
            if (preValidationCount != postValidationCount)
            {