parsePath function
Transform a path definition (value of 'd' attribute in SVG
Implementation
List<PathElement> parsePath(String pathStr) {
Tuple2<PathElement, String>? interpretCommand(
RegExp commandRegex, String input) {
var commandInterpretation = commandRegex.firstMatch(input);
if (commandInterpretation == null) return null;
var commandType = commandInterpretation.group(1)!;
var relativeCommand = commandType.toLowerCase() == commandType;
switch (commandType) {
case 'M':
case 'm':
var element = MoveElement(
relative: relativeCommand,
moveParams: Offset(double.parse(commandInterpretation.group(2)!),
double.parse(commandInterpretation.group(3)!)));
var remainingPathStr = input.substring(commandInterpretation.end);
return Tuple2<PathElement, String>(element, remainingPathStr);
case 'L':
case 'l':
var element = LineElement(
relative: relativeCommand,
lineParams: Offset(double.parse(commandInterpretation.group(2)!),
double.parse(commandInterpretation.group(3)!)));
var remainingPathStr = input.substring(commandInterpretation.end);
return Tuple2<PathElement, String>(element, remainingPathStr);
case 'c':
case 'C':
var element = CubicCurveElement(
relative: relativeCommand,
firstControlPoint: Offset(
double.parse(commandInterpretation.group(2)!),
double.parse(commandInterpretation.group(3)!)),
secondControlPoint: Offset(
double.parse(commandInterpretation.group(4)!),
double.parse(commandInterpretation.group(5)!)),
endPoint: Offset(double.parse(commandInterpretation.group(6)!),
double.parse(commandInterpretation.group(7)!)));
var remainingPathStr = input.substring(commandInterpretation.end);
return Tuple2<PathElement, String>(element, remainingPathStr);
case 'a':
case 'A':
var element = ArcElement(
relative: relativeCommand,
radius: Offset(double.parse(commandInterpretation.group(2)!),
double.parse(commandInterpretation.group(3)!)),
center: Offset(double.parse(commandInterpretation.group(7)!),
double.parse(commandInterpretation.group(8)!)),
xAxisRotation: double.parse(commandInterpretation.group(4)!));
var remainingPathStr = input.substring(commandInterpretation.end);
return Tuple2<PathElement, String>(element, remainingPathStr);
case 'z':
case 'Z':
var element = CloseElement();
var remainingPathStr = input.substring(commandInterpretation.end);
return Tuple2<PathElement, String>(element, remainingPathStr);
}
return null;
}
String valueFormat = r"(\d+(?:\.\d+)?)";
String separatorFormat = r"(?:\s+|,)";
var moveRegex =
RegExp("^(M|m)$separatorFormat$valueFormat$separatorFormat$valueFormat");
var lineRegex =
RegExp("^(L|l)$separatorFormat$valueFormat$separatorFormat$valueFormat");
var cubicCurveRegex = RegExp(
"^(C|c)$separatorFormat$valueFormat$separatorFormat" +
"$valueFormat$separatorFormat$valueFormat$separatorFormat$valueFormat$separatorFormat" +
"$valueFormat$separatorFormat$valueFormat");
var arcRegex = RegExp(
"^(A|a)$separatorFormat$valueFormat$separatorFormat$valueFormat" +
"$separatorFormat$valueFormat$separatorFormat$valueFormat$separatorFormat$valueFormat" +
"$separatorFormat$valueFormat$separatorFormat$valueFormat");
var closeRegex = RegExp("^(z)");
var elementsToReturn = <PathElement>[];
var remainingPath = pathStr.trim();
while (remainingPath.isNotEmpty) {
var moveElementTuple = interpretCommand(moveRegex, remainingPath);
var lineElementTuple = interpretCommand(lineRegex, remainingPath);
var cubicCurveElementTuple =
interpretCommand(cubicCurveRegex, remainingPath);
var arcElementTuple = interpretCommand(arcRegex, remainingPath);
var closeElementTuple = interpretCommand(closeRegex, remainingPath);
if (moveElementTuple != null) {
elementsToReturn.add(moveElementTuple.item1);
remainingPath = moveElementTuple.item2.trim();
} else if (lineElementTuple != null) {
elementsToReturn.add(lineElementTuple.item1);
remainingPath = lineElementTuple.item2.trim();
} else if (cubicCurveElementTuple != null) {
elementsToReturn.add(cubicCurveElementTuple.item1);
remainingPath = cubicCurveElementTuple.item2.trim();
} else if (arcElementTuple != null) {
elementsToReturn.add(arcElementTuple.item1);
remainingPath = arcElementTuple.item2.trim();
} else if (closeElementTuple != null) {
elementsToReturn.add(closeElementTuple.item1);
remainingPath = closeElementTuple.item2.trim();
} else
throw "Unrecognized path in $remainingPath !";
}
return elementsToReturn;
}