/// <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); }
/// <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) {