public static IVertexSource CreatePathStorage(string data) { PathStorage path = new PathStorage(); bool hasCurves = false; //todo 依次输入多个同一类型的命令时,可以省略重复的命令项;例如,L 100,200 300,400 等同于 L 100,200 L 300,400。 StringBuilder buffer = new StringBuilder(); for (int i = 0; i < data.Length; i++) { if (data[i] == '-' && i > 0 && data[i - 1] != ',' && data[i - 1] != ' ' && char.IsLetter(data[i - 1]) == false) { buffer.Append(','); } if (data[i] != 'F' && (char.IsLetter(data[i]))) { buffer.Append(','); buffer.Append(data[i]); if (i < data.Length - 1 && data[i + 1] != ' ') buffer.Append(','); } else { buffer.Append(data[i]); } } string[] commands = buffer.ToString().Split(new char[] { ' ', ',' }); MatterHackers.VectorMath.Vector2 polyStart = new MatterHackers.VectorMath.Vector2(0, 0); MatterHackers.VectorMath.Vector2 lastXY = new MatterHackers.VectorMath.Vector2(0, 0); MatterHackers.VectorMath.Vector2 curXY = new MatterHackers.VectorMath.Vector2(); for (int i = 0; i < commands.Length; i++) { switch (commands[i]) { // F0 指定 EvenOdd 填充规则。F1 指定 Nonzero 填充规则。 // 如果省略此命令,则子路径使用默认行为,即 EvenOdd。 如果指定此命令,则必须将其置于最前面。 case "F1": break; case " ": break; case "m": case "M": { curXY.x = double.Parse(commands[i + 1]); curXY.y = double.Parse(commands[i + 2]); if (commands[i] == "m") { curXY += lastXY; } path.MoveTo(curXY.x, curXY.y); polyStart = curXY; i += 2; } break; case "l": case "L": { curXY.x = double.Parse(commands[i + 1]); curXY.y = double.Parse(commands[i + 2]); if (commands[i] == "l") { curXY += lastXY; } path.LineTo(curXY.x, curXY.y); } break; case "h": case "H": { curXY.y = lastXY.y; curXY.x = double.Parse(commands[i + 1]); if (commands[i] == "h") { curXY.x += lastXY.x; } path.HorizontalLineTo(curXY.x); i += 1; } break; case "v": case "V": { curXY.x = lastXY.x; curXY.y = double.Parse(commands[i + 1]); if (commands[i] == "v") { curXY.y += lastXY.y; } path.VerticalLineTo(curXY.y); i += 1; } break; //三次方贝塞尔曲线命令。通过使用两个指定的控制点(controlPoint1 和 controlPoint2)在当前点与指定的终点之间创建一条三次方贝塞尔曲线 case "c": case "C": { MatterHackers.VectorMath.Vector2 controlPoint1; MatterHackers.VectorMath.Vector2 controlPoint2; controlPoint1.x = double.Parse(commands[i + 1]); controlPoint1.y = double.Parse(commands[i + 2]); controlPoint2.x = double.Parse(commands[i + 3]); controlPoint2.y = double.Parse(commands[i + 4]); curXY.x = double.Parse(commands[i + 5]); curXY.y = double.Parse(commands[i + 6]); if (commands[i] == "c") { controlPoint1 += lastXY; controlPoint2 += lastXY; curXY += lastXY; } path.curve4(controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, curXY.x, curXY.y); i += 6; hasCurves = true; } break; //二次贝塞尔曲线命令。通过使用指定的控制点 (controlPoint) 在当前点与指定的终点之间创建一条二次贝塞尔曲线。 case "q": case "Q": { MatterHackers.VectorMath.Vector2 controlPoint; controlPoint.x = double.Parse(commands[i + 1]); controlPoint.y = double.Parse(commands[i + 2]); curXY.x = double.Parse(commands[i + 3]); curXY.y = double.Parse(commands[i + 4]); if (commands[i] == "q") { controlPoint += lastXY; curXY += lastXY; } path.curve3(controlPoint.x, controlPoint.y, curXY.x, curXY.y); i += 4; hasCurves = true; } break; //在当前点与指定的终点之间创建一条三次方贝塞尔曲线。 //第一个控制点假定为前一个命令的第二个控制点相对于当前点的反射。 //如果前一个命令不存在,或者前一个命令不是三次方贝塞尔曲线命令或平滑的三次方贝塞尔曲线命令,则假定第一个控制点就是当前点。 //第二个控制点,即曲线终端的控制点,由 controlPoint2 指定。 case "s": case "S": { MatterHackers.VectorMath.Vector2 controlPoint2; controlPoint2.x = double.Parse(commands[i + 1]); controlPoint2.y = double.Parse(commands[i + 2]); curXY.x = double.Parse(commands[i + 3]); curXY.y = double.Parse(commands[i + 4]); if (commands[i] == "s") { controlPoint2 += lastXY; curXY += lastXY; } path.curve4(controlPoint2.x, controlPoint2.y, curXY.x, curXY.y); i += 4; hasCurves = true; } break; //二次贝塞尔曲线命令。在当前点与指定的终点之间创建一条二次贝塞尔曲线。 //控制点假定为前一个命令的控制点相对于当前点的反射。 //如果前一个命令不存在,或者前一个命令不是二次贝塞尔曲线命令或平滑的二次贝塞尔曲线命令,则此控制点就是当前点。 case "t": case "T": { curXY.x = double.Parse(commands[i + 1]); curXY.y = double.Parse(commands[i + 2]); if (commands[i] == "t") { curXY += lastXY; } path.curve3(curXY.x, curXY.y); i += 2; hasCurves = true; } break; case "z": case "Z": { curXY = lastXY; // value not used this is to remove an error. path.ClosePolygon(); // svg fonts are stored cw and agg expects its shapes to be ccw. cw shapes are holes. // We stored the position of the start of this polygon, no we flip it as we colse it. //path.invert_polygon(0); } break; case "\r": { curXY = lastXY; // value not used this is to remove an error. } break; } lastXY = curXY; } if (hasCurves == true) return new FlattenCurves(path); return path; }
public static IVertexSource PathStorageFromD(String DFromSVGFile, double xOffset, double yOffset) { PathStorage path = new PathStorage(); string[] splitOnSpace = DFromSVGFile.Split(' '); string[] splitOnComma; double xc1, yc1, xc2, yc2, x, y; for (int i = 0; i < splitOnSpace.Length; i++) { switch (splitOnSpace[i++]) { case "M": { splitOnComma = splitOnSpace[i].Split(','); double.TryParse(splitOnComma[0], NumberStyles.Number, null, out x); double.TryParse(splitOnComma[1], NumberStyles.Number, null, out y); path.MoveTo(x, y + yOffset); } break; case "L": { splitOnComma = splitOnSpace[i].Split(','); double.TryParse(splitOnComma[0], NumberStyles.Number, null, out x); double.TryParse(splitOnComma[1], NumberStyles.Number, null, out y); path.LineTo(x, y + yOffset); } break; case "C": { splitOnComma = splitOnSpace[i++].Split(','); double.TryParse(splitOnComma[0], NumberStyles.Number, null, out xc1); double.TryParse(splitOnComma[1], NumberStyles.Number, null, out yc1); splitOnComma = splitOnSpace[i++].Split(','); double.TryParse(splitOnComma[0], NumberStyles.Number, null, out xc2); double.TryParse(splitOnComma[1], NumberStyles.Number, null, out yc2); splitOnComma = splitOnSpace[i].Split(','); double.TryParse(splitOnComma[0], NumberStyles.Number, null, out x); double.TryParse(splitOnComma[1], NumberStyles.Number, null, out y); path.curve4(xc1, yc1 + yOffset, xc2, yc2 + yOffset, x, y + yOffset); } break; case "z": if (i < splitOnSpace.Length) { throw new Exception(); } break; default: throw new NotImplementedException(); } } path.arrange_orientations_all_paths(AGG.Path.FlagsAndCommand.FlagCW); VertexSourceApplyTransform flipped = new VertexSourceApplyTransform(path, Affine.NewScaling(1, -1)); return flipped; }