评论
所有者
你好, 感谢您的反馈意见! 1:我很想看代码,但我不认为我会把它包含在 OpenCNCPilot 中。有太多的设置(比如跟踪路径/跟踪外部/内部、深度(多次通过)、选项卡(不知道如何在没有适当的图形用户界面的情况下实现它,同时仍然允许在任意点放置选项卡)、v-carving 等。 .) 这将需要使它对每个人都有用,因为它太大了。我已经觉得 OpenCNCPilot 并不像我希望的那样轻巧。除此之外,OpenCNCPilot 不需要工具库,所以我不打算添加一个。 2:多种原因:
3:我不得不承认我从未尝试过。我只是不认为它真的值得:除了 PCB 之外,我还用我的 CNC 做很多事情,所以我不得不经常移除废纸板,在重新安装它之后,我需要重新面对它。探测 PCB 只需几分钟,不涉及第二个工具,并且可能仍会提供更好的结果(表面仍然会因夹紧压力等而翘曲) 干杯! |
作者
按钮代码.. [image: Inline image 3] [image: Inline image 4] Settings: [image: Inline image 2] classes added to Util..
2018 年 1 月 2 日星期二下午 1:48,Martin Pittermann ***@***.***> 写道:嗨,感谢您的反馈!1:我很想看代码,但我不认为我会把它包含在 OpenCNCPilot 中。有太多的设置(比如跟踪路径/跟踪外部/内部、深度(多次通过)、选项卡(不知道如何在没有适当的图形用户界面的情况下实现它,同时仍然允许在任意点放置选项卡)、v-carving 等。 .) 这将需要使它对每个人都有用,因为它太大了。我已经觉得 OpenCNCPilot 并不像我希望的那样轻巧。除此之外,OpenCNCPilot 不需要工具库,所以我不打算添加一个。我宁愿将 gcode 生成与 gcode 发送者分开。2:多种原因:- 周转时间:当然可以 我也从 OSHPark 订购过,但多氯联苯需要 1.5 到两周的时间才能到达德国。使用 CNC,根据项目的复杂程度,我可以在一个小时或更快的时间内完成电路板。- 单块 PCB:制造商希望重复使用掩模。OSHPark 提供了非常好的最低三块板的订购量,而且价格足以订购三块并在抽屉中保留两块,但它仍然不是最佳选择,尤其是当它只是一块普通的板时,你只想比它更永久地建造一点在穿孔板上。- 简单且大型的 PCB:例如,用于容纳按钮或 LED 阵列的 PCB,虽然数量很少,但仍然必须非常大,OSHPark 的成本会很高,如果尺寸超过 100x100mm,即使是中国供应商通常也会收取更多费用。当所需的特征尺寸较大时,您还可以使用大钻头和高进给率,从而进一步缩短时间。- 你可以在家里自己做(好吧,不是那么好。制造 PCB 对我来说已经很无聊了,就像大多数人一样,尽管这对 17 岁的我来说很酷) – 你可以将它用于很多人除了制作 PCB 之外,在不应该是直的表面上雕刻并且您没有准确的 3D 模型(例如刀片)是不可能的,如果不探测表面 3:我必须承认我’我从来没有尝试过。我只是不认为它真的值得:除了 PCB 之外,我还用我的 CNC 做很多事情,所以我不得不经常移除废纸板,在重新安装它之后,我需要重新面对它。探测 PCB 只需几分钟,不涉及第二个工具,可能仍会提供更好的结果(表面仍然会因夹紧压力等而翘曲)干杯!— 您收到此消息是因为您是该线程的作者。直接回复此邮件,在GitHub上查看 <#36(评论) >,或静音线程 < https://github.com/notifications/unsubscribe-auth/AgyLAMTApbgF6gWM7b0-Mo1DFfwtQlZRks5tGhekgaJpZM4RQfpL > 。
/* GRBL 绘图仪。GRBL 的另一个 GCode 发送器。该文件是 GRBL-Plotter 应用程序的一部分。版权所有 (C) 2015-2017 Sven Hasemann 联系方式:svenhb@web.de 本程序是免费软件:您可以根据自由软件基金会发布的 GNU 通用公共许可证的条款重新分发和/或修改它,任一版本3 的许可证,或(由您选择)任何更新版本。分发该程序是希望它有用,但不提供任何保证;甚至没有针对特定用途的适销性或适用性的默示保证。有关详细信息,请参阅 GNU 通用公共许可证。您应该已随本程序收到 GNU 通用公共许可证的副本。如果没有,请参阅 < http://www.gnu.org/licenses/>。*/ /* GCodeFromSVG.cs 一个静态类,用于将 SVG 数据转换为 G-Code 未实现:基本形状:文本、图像 变换:带偏移的旋转、skewX、skewY GCode 将写入 gcodeString[gcodeStringIndex],其中 gcodeStringIndex 对应于要绘制的元素的颜色 */ /* 2016-07-18 从形状中获取描边颜色,使用 GIMP 调色板信息查找与描边颜色相关的工具编号 添加工具更改的 gcode */ 使用系统;使用 System.Windows;使用 System.Windows.Media;使用 System.Linq;使用系统文本;使用 System.Text.RegularExpressions;使用 System.Xml.Linq;使用 System.IO;使用 System.Globalization;命名空间 OpenCNCPilot { class GCodeFromSVG { private static int svgToolMax = 100; // 最大工具数量 private static StringBuilder[] gcodeString = new StringBuilder[svgToolMax]; 私人静态 int gcodeStringIndex = 0; private static StringBuilder finalString = new StringBuilder(); // 以下设置将从 startConvert() 中的 Properties.Settings.Default 中读取 private static int svgBezierAccuracy = 6; // 在贝塞尔曲线上应用线段 private static bool svgScaleApply = true; // 如果为真,则尝试缩放最终 GCode private static float svgMaxSize = 100; // 如果应用比例,则最终 GCode 大小(更大的维度) private static bool svgClosePathExtend = true; // 如果为 true 移动到路径的第一个和第二个点以获得重叠 private static bool svgToolColor = true; // 如果为真,则取工具编号。从最近的托盘入口 private static bool svgToolSort = true; // 如果为真,则按工具编号对对象进行排序。(避免来回换笔) private static int svgToolIndex = 0; // 最后一个索引 private static bool svgNodesOnly = true; // 如果为 true,则只在给定坐标上执行 pen-down -up private static bool svgPauseElement = true; // 如果为真,则在每个元素之前插入 GCode 暂停 M0 private static bool svgPausePenDown = true; // 如果为真,则在向下工具之前插入暂停 M0 private static bool svgComments = true; // 如果为真,则在 GCode 中插入附加注释 private static bool gcodeReduce = false; // 如果为真,如果距离小于限制,则移除 G1 命令 private static float gcodeReduceVal = .1f; // 限制何时删除 G1 命令 private static float gcodeXYFeed = 2000; // XY feed申请G1 private static bool gcodeToolChange = false; // 应用工具交换命令 private static int gcodeToolNr = 0; // 将 Z 轴用于 Pen up down private static bool gcodeZApply = true; // 如果为真,则为 Pen 向上/向下插入 Z 移动 private static float gcodeZUp = 2; // Z 向上位置 private static float gcodeZDown = -2; // Z-down 位置 private static float gcodeZFeed = 500; // Z 进给申请 G1 // 使用主轴 pwr。打开/关闭激光 private static bool gcodeUseSpindle = false; // 打开/关闭刀具向下/向上 (M3/M5) 的主轴 private static bool svgConvertToMM = true; 私人静态浮动 gcodeScale = 1; // 如果 svgScaleApply 和 svgMaxSize private static Matrix[] matrixGroup = new Matrix[10]; 最后用这个因子缩放 // 存储 SVG-Group 变换矩阵 private static Matrix matrixElement = new Matrix(); // 存储最终应用的矩阵 private static Matrix oldMatrixElement = new Matrix(); // 存储最终应用的矩阵 /// <summary> /// 转换的入口点:应用文件路径或文件 URL /// </summary> /// <param name=”file”>String keeping file-name或 URL</param> /// <returns>带有导入数据 GCode 的字符串</returns> private static XElement svgCode; private static bool fromClipboard = false; public static string convertFromText(string svgText) { byte[] byteArray = Encoding.UTF8.GetBytes(svgText); MemoryStream stream = new MemoryStream(byteArray); svgCode = XElement.Load(stream, LoadOptions.None); 从剪贴板=真;返回 convertSVG(svgCode, “来自剪贴板”); // 开始转换(svgCode);} public static string convertFromFile(string file) { if (file == “”) { //MessageBox.Show(“空文件名”); 返回 ””; } if (file.Substring(0, 4) == “http”) { 字符串内容 = “”; 使用 (var wc = new System.Net. WebClient()) { 尝试 { content = wc.DownloadString(file); } catch { //MessageBox.Show(“无法从 ” + 文件加载内容); 返回 ””; } } if ((content != “”) && (content.IndexOf(“<?xml”) == 0)) { byte[] byteArray = Encoding.UTF8.GetBytes(content); MemoryStream stream = new MemoryStream(byteArray); svgCode = XElement.Load(stream, LoadOptions.None); System.Windows.Clipboard.SetData(“图像/svg+xml”, 流); 返回 convertSVG(svgCode,文件);// 开始转换(svgCode);} // 其他 // 消息框。Show(“这可能不是 SVG 文档。\r\n第一行:”+ content.Substring(0,50)); } else { if (File.Exists(file)) { try { svgCode = XElement.Load(file, LoadOptions.None); // 保留空白); 返回 convertSVG(svgCode,文件);// 开始转换(svgCode);} catch (Exception e) { //MessageBox.Show(“Error ‘” + e.ToString() + “‘ in XML file ” + file + “\r\n\r\nTry to save file with other encoding eg UTF -8”); 返回 ””; } } //else { MessageBox.Show(“文件不存在:” + file); 返回 ””; } } 返回 ””; } private static string convertSVG(XElement svgCode, string info) { gcodeStringIndex = 0; for (int i = 0; i < svgToolMax; i++) // 保留 gcode 片段以供稍后排序 { gcodeString[i] = new StringBuilder(); gcodeString[i].Clear(); } gcode.setup(); // 初始化 GCode 创建(获取导出的存储设置)finalString.Clear(); gcode.PenUp(finalString, “SVG 开始”); 开始转换(svgCode);if (gcodeUseSpindle) gcode.SpindleOn(finalString, “启动主轴 – 选项 Z 轴”); 如果(svgToolSort){ int toolnr; svg调色板。sortByToolNr(); 对于 (int i = 0; i < svgToolIndex; i++) { svgPalette.setIndex(i); // 在 svgPalette 中设置索引 toolnr = svgPalette.indexToolNr(); // 从集合索引获取值 if ((toolnr >= 0) && (gcodeString[toolnr].Length > 1)) { finalString.Append(“\r\n\r\n”); 如果 ((gcodeToolChange) && svgPalette.indexUse()) { gcode.Tool(finalString, toolnr, svgPalette.indexName()); } finalString.Append(gcodeString[toolnr]); } } } else finalString.Append(gcodeString[0]); if (gcodeUseSpindle) gcode.SpindleOff(finalString, “Stop spindle – Option Z-Axis”); string header = gcode.GetHeader(“SVG import”,info); 字符串页脚 = gcode.GetFooter(); // MessageBox.Show(“SVG 转换完成”); 返回页眉 + finalString.ToString().Replace(‘,’, ‘.’) +页脚;} /// <summary> /// 设置默认值并解析 SVG-XML 的主要元素 /// </summary> private static void startConvert(XElement svgCode) { svgBezierAccuracy = (int)Properties.Settings.Default.importSVGBezier; svgScaleApply = Properties.Settings.Default.importSVGRezise; svgMaxSize = (float)Properties.Settings.Default.importSVGMaxSize; svgClosePathExtend = Properties.Settings.Default.importSVGPathExtend; svgPauseElement = Properties.Settings.Default.importSVGPauseElement; svgPausePenDown = Properties.Settings.Default.importSVGPauseToolDown; svgComments = Properties.Settings.Default.importSVGAddComments; gcodeReduce = Properties.Settings.Default.importSVGReduce; gcodeReduceVal = (float)Properties.Settings.Default.importSVGReduceLimit; gcodeXYFeed = (float)Properties.Settings.Default.importGCXYFeed; gcodeZApply = Properties.Settings.Default.importGCZEnable; gcodeZUp = (float)Properties.Settings.Default.importGCZUp; gcodeZDown = (float)Properties.Settings.Default.importGCZDown; gcodeZFeed = (float)Properties.Settings.Default.importGCZFeed; gcodeUseSpindle = Properties.Settings.Default.importGCZEnable; svgToolColor = Properties.Settings.Default.importSVGToolColor; svgToolSort = Properties.Settings.Default.importSVGToolSort; gcodeToolChange = Properties.Settings.Default.importGCTool; svgNodesOnly = Properties.Settings.Default.importSVGNodesOnly; svgToolIndex = svgPalette.init(); startFirstElement = true; gcodeScale = 1; 当前X = 0;当前 Y = 0; 偏移量X = 0;偏移量Y = 0;矩阵元素.SetIdentity(); 对于 (int i=0; i<matrixGroup.Length;i++) matrixGroup[i].SetIdentity(); parseGlobals(svgCode);如果 (!svgNodesOnly) parseBasicElements(svgCode,1); 解析路径(svgCode,1);解析组(svgCode,1);返回; } /// <summary> /// 解析 SVG 维度(视图框、宽度、高度) /// </summary> private static XNamespace nspace = “http://www.w3.org/2000/svgvbHeight = floatParse(split[3].TrimEnd(‘)’)); tmp.M11 = 1; tmp.M22 = -1; // 翻转 Y tmp.OffsetY = vbHeight; 如果 (svgComments) gcodeString[gcodeStringIndex].AppendLine(“( SVG viewbox :” + viewbox+” )”); } if (svgCode.Attribute(“width”) != null) { tmpString = svgCode.Attribute(“width”).Value; svgWidthPx = floatParse(tmpString); 如果 (svgConvertToMM && tmpString.IndexOf(“in”)>0) scale = 25.4f; tmpString = removeUnit(tmpString); float svgWidthUnit = floatParse(tmpString);//floatParse(svgCode.Attribute(“width”).Value.Replace(“mm”, “”)); 如果 (svgComments) gcodeString[gcodeStringIndex].AppendLine(“( SVG 宽度:” + svgCode.Attribute(“width”).Value + ” )”); tmp.M11 = scale * svgWidthUnit / svgWidthPx; // 获得所需比例 if (fromClipboard) tmp.M11 = 1 / 3.543307; if (vbWidth > 0) { tmp.M11 = scale * svgWidthPx / vbWidth; tmp.OffsetX = vbOffX * svgWidthUnit / vbWidth; } } if (svgCode.Attribute(“height”) != null) { tmpString = svgCode.Attribute(“height”).Value; svgHeightPx = floatParse(tmpString); 如果 (svgConvertToMM && tmpString.IndexOf(“in”) > 0) scale = 25.4f; tmpString = removeUnit(tmpString); float svgHeightUnit = floatParse(tmpString);// svgCode.Attribute(“height”).Value.Replace(“mm”, “”)); 如果 (svgComments) gcodeString[gcodeStringIndex].AppendLine(“( SVG 高度:” + svgCode.Attribute(“height”).Value + ” )”); tmp.M22 = -scale * svgHeightUnit / svgHeightPx; // 获得所需比例并垂直翻转 tmp.OffsetY = svgHeightUnit ; 如果(来自剪贴板){ tmp.M22 = -1 / 3.543307; tmp.OffsetY = svgHeightUnit / 3.543307; } if (vbHeight > 0) { tmp.M22 = -scale * svgHeightPx / vbHeight; tmp.OffsetY = -vbOffX * svgHeightUnit / vbHeight + svgHeightPx; } } for (int i = 0; i < matrixGroup.Length; i++) { matrixGroup[i] = tmp; } 矩阵元素 = tmp; if (svgComments) gcodeString[gcodeStringIndex].AppendFormat(“( Inital Matrix {0} )\r\n”, tmp.ToString()); 如果 ((svgWidthPx > 0) && (svgHeightPx > 0)) { 如果 (svgScaleApply) { gcodeScale = svgMaxSize / Math.Max(svgWidthPx, svgHeightPx); 如果 (svgComments) gcodeString[gcodeStringIndex].AppendFormat(“( 缩放到 X={0} Y={1} f={2} )\r\n”, svgWidthPx * gcodeScale, svgHeightPx * gcodeScale, gcodeScale); } } else if (svgComments) gcodeString[gcodeStringIndex].Append(” 解析路径(组元素,级别);parseGroup(groupElement, level+1); } 返回; } /// <summary> /// 解析转换信息——更多信息在这里:http://www.w3.org/TR/SVG/coords.html /// 转换将应用于 gcodeMove /// </summary> private static void parseTransform(XElement element,bool isGroup, int level) { Matrix tmp = new Matrix(1, 0, 0, 1, 0, 0); // m11, m12, m21, m22, offsetx, offsety bool transf = false; if (element.Attribute(“transform”) != null) { transf = true; string transform = element.Attribute(“transform”).Value; if ((transform != null) && (transform.IndexOf(“translate”) >= 0)) { var coord = getTextBetween(transform, “translate(“, “)”); var split = coord.Split(‘,’); 如果 (coord.IndexOf(‘,’) < 0) split = coord.Split(‘ ‘); //MessageBox.Show(transform+”\r\n>”+coord + “< “+ split[0]); tmp.OffsetX = floatParse(split[0]); 如果 (split.Length > 1) tmp.OffsetY = floatParse(split[1].TrimEnd(‘)’)); 如果 (svgComments) gcodeString[gcodeStringIndex].Append(string.Format(“( SVG-Translate {0} {1} )\r\n”, tmp.OffsetX, tmp.OffsetY)); } if ((transform != null) && (transform.IndexOf(“scale”) >= 0)) { var coord = getTextBetween(transform, “scale(“, “)”); var split = coord.Split(‘,’); 如果 (coord.IndexOf(‘,’) < 0) split = coord.Split(‘ ‘); tmp.M11 = floatParse(split[0]); 如果 (split.Length > 1) { tmp.M22 = floatParse(split[1]); } else { tmp.M11 = floatParse(坐标); tmp.M22 = floatParse(坐标); } if (svgComments) gcodeString[gcodeStringIndex].Append(string.Format(“( SVG-Scale {0} {1} )\r\n”, tmp.M11, tmp.M22)); } if ((transform != null) && (transform.IndexOf(“rotate”) >= 0)) { var coord = getTextBetween(transform, “rotate(“, “)”); var split = coord.Split(‘,’); 如果(协调。IndexOf(‘,’) < 0) split = coord.Split(‘ ‘); 浮动角度 = floatParse(split[0]) * (float)Math.PI / 180; tmp.M11 = Math.Cos(角度); tmp.M12 = Math.Sin(角度); tmp.M21 = -Math.Sin(角度); tmp.M22 = Math.Cos(角度); 如果 (svgComments) gcodeString[gcodeStringIndex].Append(string.Format(“( SVG-Rotate {0} )\r\n”, angle)); } if ((transform != null) && (transform.IndexOf(“matrix”) >= 0)) { var coord = getTextBetween(transform, “matrix(“, “)”); var split = coord.Split(‘,’); 如果 (coord.IndexOf(‘,’) < 0) split = coord.Split(‘ ‘); tmp.M11 = floatParse(split[0]); // 比例尺 xace tmp.M12 = floatParse(split[1]); // bbdf tmp.M21 = floatParse(split[2]); // c 0 0 1 tmp.M22 = floatParse(split[3]); // d 缩放 y tmp.OffsetX = floatParse(split[4]); // e 偏移 x tmp.OffsetY = floatParse(split[5]); // f 偏移 y if (svgComments) gcodeString[gcodeStringIndex].Append(string.Format(“\r\n( SVG-Matrix {0} {1} {2} )\r\n”, coord.Replace(‘ ,’, ‘|’), 级别, isGroup)); } //} if (isGroup) { matrixGroup[level].SetIdentity(); 如果(水平> 0) { for (int i = level; i < matrixGroup.Length; i++) { matrixGroup[i] = Matrix.Multiply(tmp, matrixGroup[level – 1]); } } else { matrixGroup[level] = tmp; } matrixElement = matrixGroup[level]; } else { matrixElement = Matrix.Multiply(tmp, matrixGroup[level]); } if (svgComments && transf) { for (int i = 0; i <= level; i++) gcodeString[gcodeStringIndex].AppendFormat(“( gc-Matrix level[{0}] {1} )\r\n”, i, matrixGroup[i].ToString()); 如果 (svgComments) gcodeString[gcodeStringIndex].AppendFormat(” } private static float floatParse(string str, float ext=1) { bool percent = false; 浮动因子= 1;如果 (str.IndexOf(“pt”) > 0) { 因子 = 1.25f; } 如果 (str.IndexOf(“pc”) > 0) { factor = 15f; } if (str.IndexOf(“mm”) > 0) { factor = 3.543307f; } if (str.IndexOf(“cm”) > 0) { factor = 35.43307f; } if (str.IndexOf(“in”) > 0) { factor = 90f; } 如果 (str.IndexOf(“em”) > 0) { factor = 150f; } if (str.IndexOf(“%”) > 0) { percent = true; } str = str.Replace(“pt”, “”).Replace(“pc”, “”).Replace(“mm”, “”).Replace(“cm”, “”).Replace(“in” , “”).Replace(“em”, “”).Replace(“%”, “”).Replace(“px”, “”); if (str.Length > 0) { if (percent) return float.Parse(str, CultureInfo.InvariantCulture.NumberFormat) * ext / 100; 否则返回 float.Parse(str, CultureInfo.InvariantCulture.NumberFormat) * factor; }否则返回0f;} private static string removeUnit(string str) { return str.Replace(“pt”, “”).Replace(“pc”, “”).Replace(“mm”, “”).Replace(“cm”, ” “).Replace(“in”, “”).Replace(“em”, “”).Replace(“%”, “”).Replace(“px”, “”); } private static string getColor(XElement pathElement) { string style = “”; 字符串 stroke_color = “000000”; // default=black if (pathElement.Attribute(“style”) != null) { int start, end; style = pathElement.Attribute(“style”).Value; start = style.IndexOf(“中风:#”); if (start >= 0) { end = style.IndexOf(‘;’, start); if (end > start) stroke_color = style.Substring(start + 8, end – start – 8); } 返回笔画颜色;} 返回 ””; } /// <总结>http://www.w3.org/TR/SVG/shapes.html /// </summary> private static void parseBasicElements(XElement svgCode, int level) { string[] forms = { “rect”, “circle”, “ellipse”, “line”, “polyline”, “polygon”, “文字”, “图像” }; foreach (var form in forms) { foreach (var pathElement in svgCode.Elements(nspace + form)) { if (pathElement != null) { string myColor = getColor(pathElement); int myTool = svgPalette.getToolNr(myColor,0); 如果 ((svgToolSort) && (myTool >= 0)) gcodeStringIndex = myTool; if (svgComments) { if (pathElement.Attribute(“id”) != null) gcodeString[gcodeStringIndex].Append(“\r\n( 基本形状级别:” + level.ToString() + ” id=” + pathElement .Attribute(“id”).Value + ” )\r\n”); gcodeString[gcodeStringIndex].AppendFormat(“( SVG color=#{0})\r\n”, myColor); } gcodeTool(我的工具);如果(startFirstElement){ gcodePenUp(“第一个形状”); startFirstElement = false; } 偏移量X = 0; 偏移量Y = 0;旧矩阵元素 = 矩阵元素;parseTransform(pathElement, false, level); // 变换将应用于 gcodeMove float x=0, y=0, x1=0, y1=0, x2=0, y2=0, width=0, height=0, rx=0, ry=0,cx =0,cy=0,r=0; 字符串 [] 点 = {“”}; 如果 (pathElement.Attribute(“x”) !=null) x = floatParse(pathElement.Attribute(“x”).Value); 如果 (pathElement.Attribute(“y”) != null) y = floatParse(pathElement.Attribute(“y”).Value); 如果 (pathElement.Attribute(“x1”) != null) x1 = floatParse(pathElement.Attribute(“x1”).Value); 如果 (pathElement.Attribute(“y1”) != null) y1 = floatParse(pathElement.Attribute(“y1”).Value); 如果(路径元素。属性(“x2”)!= null) x2 = floatParse(pathElement.Attribute(“x2”).Value); 如果 (pathElement.Attribute(“y2”) != null) y2 = floatParse(pathElement.Attribute(“y2”).Value); 如果 (pathElement.Attribute(“width”) != null) width =floatParse(pathElement.Attribute(“width”).Value, svgWidthPx); 如果 (pathElement.Attribute(“height”) != null) height=floatParse(pathElement.Attribute(“height”).Value, svgHeightPx); 如果 (pathElement.Attribute(“rx”) != null) rx=floatParse(pathElement.Attribute(“rx”).Value); 如果 (pathElement.Attribute(“ry”) != null) ry=floatParse(pathElement.Attribute(“ry”).Value); 如果(路径元素。Attribute(“cx”) != null) cx=floatParse(pathElement.Attribute(“cx”).Value); 如果 (pathElement.Attribute(“cy”) != null) cy=floatParse(pathElement.Attribute(“cy”).Value); 如果 (pathElement.Attribute(“r”) != null) r=floatParse(pathElement.Attribute(“r”).Value); 如果 (pathElement.Attribute(“points”) != null) points = pathElement.Attribute(“points”).Value.Split(‘ ‘); if (svgPauseElement||svgPausePenDown) { gcode.Pause(gcodeString[gcodeStringIndex], “路径前暂停”); } if (form == “rect”) { if (ry == 0) { ry = rx; } else if (rx == 0) { rx = ry; } if (svgComments) gcodeString[gcodeStringIndex].AppendFormat(“( SVG-Rect x:{0} y:{1} width:{2} height:{3} )\r\n”, x, y, width,高度); x += 偏移量X;y += 偏移量 Y;gcodeStartPath(x + rx, y + height, form); gcodeMoveTo(x + width – rx, y + height, form); if (rx > 0) gcodeArcToCCW(x + width, y + height – ry, 0, ry, form); gcodeMoveTo(x + width, y + ry, form); // 右上角 if (rx > 0) gcodeArcToCCW(x + width – rx, y, -rx, 0, form); gcodeMoveTo(x + rx, y, 形式); // 左上角 if (rx > 0) gcodeArcToCCW(x, y + ry, 0, -ry, form); gcodeMoveTo(x, y + height – ry, form); // 左下角 if (rx > 0) gcodeArcToCCW(x + rx, y + height, rx, 0, form); gcodeStopPath(形式); } else if (form == “circle”) { if (svgComments) gcodeString[gcodeStringIndex].AppendFormat(“( circle cx:{0} cy:{1} r:{2} )\r\n”, cx, cy, r); cx += 偏移量X;cy += 偏移量 Y;gcodeStartPath(cx + r, cy, form); gcodeArcToCCW(cx + r, cy, -r, 0, 形式); gcodeStopPath(形式); }否则如果(形式==“椭圆” ) { if (svgComments) gcodeString[gcodeStringIndex].AppendFormat(“( 椭圆 cx:{0} cy:{1} rx:{2} ry:{2})\r\n”, cx, cy, rx, ry ); cx += 偏移量X;cy += 偏移量 Y;gcodeStartPath(cx + rx, cy, form); isReduceOk = true; calcArc(cx + rx, cy, rx, ry, 0, 1, 1, cx – rx, cy); calcArc(cx – rx, cy, rx, ry, 0, 1, 1, cx + rx, cy); gcodeStopPath(形式); } else if (form == “line”) { if (svgComments) gcodeString[gcodeStringIndex].AppendFormat(“( SVG-Line x1:{0} y1:{1} x2:{2} y2:{3} )\ r\n”, x1, y1, x2, y2); x1 += 偏移量X;y1 += 偏移量 Y;gcodeStartPath(x1, y1, 形式); gcodeMoveTo(x2, y2, 形式); gcodeStopPath(形式); } else if ((form == “polyline”) || (form == “polygon”)) { offsetX = 0;// (float)matrixElement.OffsetX; offsetY = 0;// (float)matrixElement.OffsetY; 如果 (svgComments) gcodeString[gcodeStringIndex].AppendFormat(“( SVG-Polyline )\r\n”); 整数索引 = 0;for (index = 0; index < points.Length; index++) { if (points[index].Length > 0) 中断;} if (points[index].IndexOf(“,”) >= 0) { string[] coord = points[index].Split(‘,’); x = floatParse(坐标[0]); y = floatParse(坐标 [1]); x1 = x; y1 = y; gcodeStartPath(x, y, 形式); isReduceOk = true; 对于 (int i = index + 1; i < points.Length; i++) { if (points[i].Length > 3) { coord = points[i].Split(‘,’); x = floatParse(坐标[0]); y = floatParse(坐标 [1]); x += 偏移量X;y += 偏移量 Y;gcodeMoveTo(x, y, 形式); } } if (form == “polygon”) gcodeMoveTo(x1, y1, form); gcodeStopPath(形式); } else gcodeString[gcodeStringIndex].AppendLine(“( 多边形坐标 – 缺少 ‘,’)”); } else if ((form == “text”) || (form == “image” )) { gcodeString[gcodeStringIndex].AppendLine(“( +++++++++++++++++++++++++++++++++)”); gcodeString[gcodeStringIndex].AppendLine(“( ++++++ ” + form + ” 不支持 ++++ )”); if (form == “text”) { gcodeString[gcodeStringIndex].AppendLine(“( ++ Convert Object to Path first + )”); } gcodeString[gcodeStringIndex].AppendLine(“( +++++++++++++++++++++++++++++++++)”); } else { if (svgComments) gcodeString[gcodeStringIndex].Append(“( ++++++ Unknown Shape: ” + form + ” )”); } matrixElement = oldMatrixElement; } } } 返回; } /// <summary> /// 转换所有路径命令,检查:http://www.w3.org/TR/SVG/paths.html /// 拆分命令标记 /// </summary> private static void parsePath(XElement svgCode, int level) { foreach (var pathElement in svgCode.Elements(nspace + “path”)) { if (pathElement != null) { offsetX = 0;// (float)matrixElement.OffsetX; offsetY = 0;// (float)matrixElement.OffsetY; 当前 X = 偏移量 X;当前 Y = 偏移量 X;第一个 X = 空;第一个 Y = 空;开始路径=真;开始子路径=真;lastX = 偏移量X;lastY = 偏移量 Y;string d = pathElement.Attribute(“d”).Value; 字符串id = d; 如果(id.Length > 20)id = id。子串(0, 20); 字符串 myColor = getColor(pathElement); int myTool = svgPalette.getToolNr(myColor,0);// svgToolTable[myIndex].toolnr; if ((svgToolSort) && (myTool >= 0)) { if(penIsDown) gcodePenUp(“开始路径”); gcodeStringIndex = myTool; } // gcodeString[gcodeStringIndex].Append(“(起始路径)\r\n”); if (svgComments) { if (pathElement.Attribute(“id”) != null) gcodeString[gcodeStringIndex].Append(“\r\n( 路径级别:” + level.ToString() + ” id=” + pathElement。 Attribute(“id”).Value + ” )\r\n”); 否则 gcodeString[gcodeStringIndex].Append(“\r\n( SVG path=” + id + ” )\r\n”); gcodeString[gcodeStringIndex].AppendFormat(“\r\n(SVG color=#{0})\r\n”, myColor); } if (pathElement.Attribute(“id”) != null) id = pathElement.Attribute(“id”).Value; 旧矩阵元素 = 矩阵元素;parseTransform(pathElement,false,level); // 转换将应用于 gcodeMove gcodeTool(myTool); if (d.Length > 0) { // 将完整路径拆分为命令标记 if (svgPauseElement||svgPausePenDown) { gcode. Pause(gcodeString[gcodeStringIndex], “路径前暂停”); } 字符串分隔符 = @”(?=[A-Za-z-[e]])”; var tokens = Regex.Split(d, separators).Where(t => !string.IsNullOrEmpty(t)); int objCount = 0; foreach(令牌中的字符串令牌)objCount += parsePathCommand(令牌);} gcodePenUp(“结束路径”); 矩阵元素 = 旧矩阵元素;} } 返回; } private static bool penIsDown = true; private static bool startSubPath = true; private static bool startPath = true; private static bool startFirstElement = true; 私有静态浮动 svgWidthPx,svgHeightPx;私有静态浮动 offsetX,offsetY;私有静态浮动电流X,电流Y;私人静态浮动?第一个X,第一个Y;私有静态浮动 lastX,lastY;私有静态浮动 cxMirror=0,cyMirror=0;private static StringBuilder secondMove = new StringBuilder(); /// <summary> /// 转换所有路径命令,检查:http://www.w3.org/TR/SVG/paths.html /// 转换命令标记 /// </summary> private static int parsePathCommand(string svgPath) { var command = svgPath.Take(1).Single(); char cmd = char.ToUpper(命令); 布尔绝对=(cmd==命令);字符串 remainingargs = svgPath.Substring(1); string argSeparators = @”[\s,]|(?=(?<!e)-)”;// @”[\s,]|(?=-)|(-{,2})”; // 也支持 -1.2e-3 @”[\s,]|(?=-)”; var splitArgs = Regex .Split(remainingargs, argSeparators) .Where(t => !string.IsNullOrEmpty(t)); // 获取命令坐标 float[] floatArgs = splitArgs.Select(arg => floatParse(arg)).ToArray(); int objCount = 0; 开关(cmd){ 案例’ M’: // 在给定的 (x,y) 坐标开始一个新的子路径 for (int i = 0; i < floatArgs.Length; i += 2) { objCount++; if (absolute || startPath) { currentX = floatArgs[i] + offsetX; currentY = floatArgs[i + 1] + offsetY; } else { currentX = floatArgs[i] + lastX; currentY = floatArgs[i + 1] + lastY; } if (startSubPath) { if (svgComments) { gcodeString[gcodeStringIndex].AppendFormat(“( 在 {0} {1} 开始新的子路径)\r\n”, floatArgs[i], floatArgs[i+1]); } // 路径计数 = 0; // gcodeStopPath(“”); 如果 (svgNodesOnly) gcodeDotOnly(currentX, currentY, command.ToString()); 否则 gcodeStartPath(currentX, currentY, command.ToString()); isReduceOk = true; 第一个 X = 当前 X;第一个 Y = 当前 Y;开始路径=假;startSubPath = false; } else { if (svgNodesOnly) gcodeDotOnly(currentX, currentY, command.ToString()); 否则 gcodeMoveTo(currentX, currentY, command.ToString()); // G1 } if (firstX == null) { firstX = currentX; } if (firstY == null) { firstY = currentY; } lastX = currentX; 最后 Y = 当前 Y;} cxMirror = currentX; cyMirror = currentY; 休息; case ‘Z’: // 关闭当前子路径 if (!svgNodesOnly) { if (firstX == null) { firstX = currentX; } if (firstY == null) { firstY = currentY; } gcodeMoveTo((float)firstX, (float)firstY, command.ToString()); // G1 } lastX = (float)firstX; lastY = (浮动)firstY; 第一个 X = 空;第一个 Y = 空;开始子路径=真;如果 ((svgClosePathExtend) && (!svgNodesOnly)) { gcodeString[gcodeStringIndex].Append(secondMove); } gcodeStopPath(“Z”); 休息; case ‘L’: // 从当前点到给定的 (x,y) 坐标画一条线 for (int i = 0; i < floatArgs.Length; i += 2) { objCount++; 如果(绝对){ currentX = floatArgs[i] + offsetX; currentY = floatArgs[i + 1] + offsetY; } else { currentX = lastX + floatArgs[i]; currentY = lastY + floatArgs[i + 1]; } 如果 (svgNodesOnly) gcodeDotOnly(currentX, currentY, command.ToString()); 否则 gcodeMoveTo(currentX, currentY, command.ToString()); lastX = 当前 X; 最后 Y = 当前 Y;cxMirror = currentX; cyMirror = currentY; } startSubPath = true; 休息; case ‘H’: // 从当前点 (cpx, cpy) 到 (x, cpy) 画一条水平线 for (int i = 0; i < floatArgs.Length; i ++) { objCount++; 如果(绝对){ currentX = floatArgs[i] + offsetX; 当前 Y = 最后 Y;} else { currentX = lastX + floatArgs[i]; 当前 Y = 最后 Y;} 如果 (svgNodesOnly) gcodeDotOnly(currentX, currentY, command.ToString()); 否则 gcodeMoveTo(currentX, currentY, command.ToString()); lastX = 当前 X; 最后 Y = 当前 Y;cxMirror = currentX; cyMirror = currentY; } startSubPath = true; 休息; case ‘V’: // 从当前点 (cpx, cpy) 到 (cpx, y) 画一条垂直线 for (int i = 0; i < floatArgs.Length; i++) { objCount++; 如果(绝对){ currentX = lastX; currentY = floatArgs[i] + offsetY; } else { currentX = lastX ; currentY = lastY + floatArgs[i]; } 如果 (svgNodesOnly) gcodeDotOnly(currentX, currentY, command.ToString()); 否则 gcodeMoveTo(currentX, currentY, command.ToString()); lastX = 当前 X; 最后 Y = 当前 Y;cxMirror = currentX; cyMirror = currentY; } startSubPath = true; 休息; case ‘A’: // 绘制一条从当前点到 (x, y) 的椭圆弧 if (svgComments) { gcodeString[gcodeStringIndex]. AppendFormat(“( 命令 {0} {1} )\r\n”, command.ToString(), ((absolute == true) ? “absolute” : “relative”)); } for (int rep = 0; rep < floatArgs.Length; rep += 7) { objCount++; if (svgComments) { gcodeString[gcodeStringIndex].AppendFormat(“( draw arc nr. {0} )\r\n”, (1 + rep / 6)); } float rx,ry,rot,large,sweep,nx,ny; rx = floatArgs[rep] ; ry = floatArgs[rep + 1] ; rot = floatArgs[rep + 2]; 大 = floatArgs[rep + 3]; sweep = floatArgs[rep + 4]; 如果(绝对){ nx = floatArgs[rep + 5] + offsetX ; ny = floatArgs[rep + 6] + offsetY; } else { nx = floatArgs[rep + 5] + lastX ; ny = floatArgs[rep + 6] + lastY; } 如果 (svgNodesOnly) gcodeDotOnly(currentX, currentY, command.ToString()); else calcArc(lastX, lastY, rx, ry, rot, large, sweep, nx, ny); lastX = nx; 最后Y=纽约;} startSubPath = true; 休息; case ‘C’: // 绘制从当前点到 (x,y) 的三次贝塞尔曲线 if (svgComments) { gcodeString[gcodeStringIndex].AppendFormat(“( Command {0} {1} )\r\n”,命令.ToString(), ((绝对==真)?“绝对”:“相对”));} for (int rep = 0; rep < floatArgs.Length; rep += 6) { objCount++; if (svgComments) { gcodeString[gcodeStringIndex].AppendFormat(“( 绘制曲线 nr. {0} )\r\n”, (1 + rep / 6)); } if ((rep + 5) < floatArgs.Length) { float cx1, cy1, cx2, cy2, cx3, cy3; 如果(绝对){ cx1 = floatArgs[rep] + offsetX; cy1 = floatArgs[rep + 1] + offsetY; cx2 = floatArgs[rep + 2] + offsetX; cy2 = floatArgs[rep + 3] + offsetY; cx3 = floatArgs[rep + 4] + offsetX; cy3 = floatArgs[rep + 5] + offsetY; } else { cx1 = lastX + floatArgs[rep]; cy1 = lastY + floatArgs[rep + 1]; cx2 = lastX + floatArgs[rep + 2]; cy2 = lastY + floatArgs[rep + 3]; cx3 = lastX + floatArgs[rep + 4]; cy3 = lastY + floatArgs[rep + 5]; } points = new Point[4]; points[0] = new Point(lastX, lastY); points[1] = new Point(cx1, cy1); points[2] = new Point(cx2, cy2); points[3] = new Point(cx3, cy3); var b = GetBezierApproximation(点,svgBezierAccuracy);if (svgNodesOnly) { //gcodeDotOnly(cx1, cy1, command.ToString()); //gcodeDotOnly(cx2, cy2, command.ToString()); gcodeDotOnly(cx3, cy3, command.ToString()); } else { for (int i = 1; i < b.Points.Count; i++) gcodeMoveTo((float)b.Points[i].X, (float)b.Points[i].Y, command.ToString( )); } cxMirror = cx3 – (cx2 – cx3); cyMirror = cy3 – (cy2 – cy3); lastX = cx3; lastY = cy3; } else { gcodeString[gcodeStringIndex].AppendFormat(“( {0} 后缺少参数)\r\n”, rep); } } startSubPath = true; 休息; case ‘S’: // 绘制从当前点到 (x,y) 的三次贝塞尔曲线 if (svgComments) { gcodeString[gcodeStringIndex].AppendFormat(“( Command {0} {1} )\r\n”, command.ToString(), ((absolute == true) ? “absolute” : “relative”)); } for (int rep = 0; rep < floatArgs.Length; rep += 4) { objCount++; if (svgComments) { gcodeString[gcodeStringIndex].AppendFormat(“( 绘制曲线 nr. {0} )\r\n”, (1 + rep / 4)); }浮动cx2,cy2,cx3,cy3;如果(绝对){ cx2 = floatArgs[rep] + offsetX; cy2 = floatArgs[rep + 1] + offsetY; cx3 = floatArgs[rep + 2] + offsetX; cy3 = floatArgs[rep + 3] + offsetY; } else { cx2 = lastX + floatArgs[rep]; cy2 = lastY + floatArgs[rep + 1]; cx3 = lastX + floatArgs[rep + 2]; cy3 = lastY + floatArgs[rep + 3]; } points = new Point[4]; points[0] = new Point(lastX, lastY); points[1] = new Point(cxMirror, cyMirror); points[2] = new Point(cx2, cy2); points[3] = new Point(cx3, cy3); var b = GetBezierApproximation(点,svgBezierAccuracy);if (svgNodesOnly) { //gcodeDotOnly(cxMirror, cyMirror, command.ToString()); //gcodeDotOnly(cx2, cy2, command.ToString()); gcodeDotOnly(cx3, cy3, command.ToString()); } else { for (int i = 1; i < b.Points.Count; i++) gcodeMoveTo((float)b.Points[i].X, (float)b.Points[i].Y, command.ToString( )); } cxMirror = cx3 – (cx2 – cx3); cyMirror = cy3 – (cy2 – cy3); lastX = cx3; lastY = cy3; } startSubPath = true; 休息; case ‘Q’: // 绘制从当前点到 (x,y) 的二次贝塞尔曲线 if (svgComments) { gcodeString[gcodeStringIndex].AppendFormat(“( Command {0} {1} )\r\n”, command.ToString(), ((absolute == true) ? “absolute” : “relative”)); } for (int rep = 0; rep < floatArgs.Length; rep += 4) { objCount++; if (svgComments) { gcodeString[gcodeStringIndex].AppendFormat(“( 绘制曲线 nr. {0} )\r\n”, (1 + rep / 4)); }浮动cx2,cy2,cx3,cy3;如果(绝对){ cx2 = floatArgs[rep] + offsetX; cy2 = floatArgs[rep + 1] + offsetY; cx3 = floatArgs[rep + 2] + offsetX; cy3 = floatArgs[rep + 3] + offsetY; } else { cx2 = lastX + floatArgs[rep]; cy2 = lastY + floatArgs[rep + 1]; cx3 = lastX + floatArgs[rep + 2]; cy3 = lastY + floatArgs[rep + 3]; } float qpx1 = (cx2 – lastX) * 2 / 3 + lastX; // 将控制点缩短到 2/3 长度以使用 float qpy1 = (cy2 – lastY) * 2 / 3 + lastY; // qubic 函数 float qpx2 = (cx2 – cx3) * 2 / 3 + cx3; 浮动 qpy2 = (cy2 – cy3) * 2 / 3 + cy3; 点=新点[4];points[0] = new Point(lastX, lastY); points[1] = new Point(qpx1, qpy1); points[2] = new Point(qpx2, qpy2); points[3] = new Point(cx3, cy3); cxMirror = cx3 – (cx2 – cx3); cyMirror = cy3 – (cy2 – cy3); lastX = cx3; lastY = cy3; var b = GetBezierApproximation(点,svgBezierAccuracy);if (svgNodesOnly) { //gcodeDotOnly(qpx1, qpy1, command.ToString()); //gcodeDotOnly(qpx2, qpy2, command.ToString()); gcodeDotOnly(cx3, cy3, command.ToString()); } else { for (int i = 1; i < b.Points.Count; i++) gcodeMoveTo((float)b.Points[i].X, (float)b.Points[i].Y, command.ToString( )); } } startSubPath = true; 休息; case ‘T’: // 绘制从当前点到 (x,y) 的二次贝塞尔曲线 if (svgComments) { gcodeString[gcodeStringIndex].AppendFormat(“( Command {0} {1} )\r\n”, command.ToString(), ((absolute == true) ? “absolute” : “relative”)); } for (int rep = 0; rep < floatArgs.Length; rep += 2) { objCount++; if (svgComments) { gcodeString[gcodeStringIndex].AppendFormat(“( 绘制曲线 nr. {0} )\r\n”, (1 + rep / 2)); }浮动cx3,cy3;如果(绝对){ cx3 = floatArgs[rep] + offsetX; cy3 = floatArgs[rep + 1] + offsetY; } else { cx3 = lastX + floatArgs[rep]; cy3 = lastY + floatArgs[rep + 1]; } float qpx1 = (cxMirror – lastX) * 2 / 3 + lastX; // 将控制点缩短到 2/3 长度以使用 float qpy1 = (cyMirror – lastY) * 2 / 3 + lastY; // qubic 函数 float qpx2 = (cxMirror – cx3) * 2 / 3 + cx3; 浮动 qpy2 = (cyMirror – cy3) * 2 / 3 + cy3; 点=新点[4];points[0] = new Point(lastX, lastY); points[1] = new Point(qpx1, qpy1); points[2] = new Point(qpx2, qpy2); points[3] = new Point(cx3, cy3); cxMirror = cx3; cyMirror = cy3; lastX = cx3; lastY = cy3; var b = GetBezierApproximation(点,svgBezierAccuracy);if (svgNodesOnly) { //gcodeDotOnly(qpx1, qpy1, command.ToString()); //gcodeDotOnly(qpx2, qpy2, command.ToString()); gcodeDotOnly(cx3, cy3, command.ToString()); } else { for (int i = 1; i < b.Points.Count; i++) gcodeMoveTo((float)b.Points[i].X, (float)b.Points[i].Y, command.ToString( )); } } startSubPath = true; 休息; 默认值:if (svgComments) gcodeString[gcodeStringIndex].Append(“( *********** unknown: ” + command.ToString()+ ” ***** )\r\n”); 休息; } 返回对象数;} /// <summary> /// 计算 Path-Arc-Command – 代码来自 i++) gcodeMoveTo((float)b.Points[i].X, (float)b.Points[i].Y, command.ToString()); } } startSubPath = true; 休息; 默认值:if (svgComments) gcodeString[gcodeStringIndex].Append(“( *********** unknown: ” + command.ToString()+ ” ***** )\r\n”); 休息; } 返回对象数;} /// <summary> /// 计算 Path-Arc-Command – 代码来自 i++) gcodeMoveTo((float)b.Points[i].X, (float)b.Points[i].Y, command.ToString()); } } startSubPath = true; 休息; 默认值:if (svgComments) gcodeString[gcodeStringIndex].Append(“( *********** unknown: ” + command.ToString()+ ” ***** )\r\n”); 休息; } 返回对象数;} /// <summary> /// 计算 Path-Arc-Command – 代码来自 如果 (svgComments) gcodeString[gcodeStringIndex].Append(“( *********** 未知: ” + command.ToString()+ ” ***** )\r\n”); 休息; } 返回对象数;} /// <summary> /// 计算 Path-Arc-Command – 代码来自 如果 (svgComments) gcodeString[gcodeStringIndex].Append(“( *********** 未知: ” + command.ToString()+ ” ***** )\r\n”); 休息; } 返回对象数;} /// <summary> /// 计算 Path-Arc-Command – 代码来自https://github.com/vvvv/SVG/blob/master/Source/Paths/SvgArcSegment.cs /// </summary> private static void calcArc(float StartX, float StartY, float RadiusX, float RadiusY,float Angle, float Size, float Sweep, float EndX, float EndY) { if (RadiusX == 0.0f && RadiusY = = 0.0f) { // graphicsPath.AddLine(this.Start, this.End); 返回; } double sinPhi = Math.Sin(Angle * Math.PI / 180.0); 双 cosPhi = Math.Cos(角度 * Math.PI / 180.0); 双 x1dash = cosPhi * (StartX – EndX) / 2.0 + sinPhi * (StartY – EndY) / 2.0; 双 y1dash = -sinPhi * (StartX – EndX) / 2.0 + cosPhi * (StartY – EndY) / 2.0; 双根; 双分子 = RadiusX * RadiusX * RadiusY * RadiusY – RadiusX * RadiusX * y1dash * y1dash – RadiusY * RadiusY * x1dash * x1dash;float rx = RadiusX; 浮动 ry = RadiusY; if (numerator < 0.0) { float s = (float)Math.Sqrt(1.0 – 分子 / (RadiusX * RadiusX * RadiusY * RadiusY)); 接收*=小号; 里 * = 小号; 根 = 0.0;} else { root = ((Size == 1 && Sweep == 1) || (Size == 0 && Sweep == 0) ? -1.0 : 1.0) * Math.Sqrt(numerator / (RadiusX * RadiusX * y1dash * y1dash + RadiusY * RadiusY * x1dash * x1dash)); } double cxdash = root * rx * y1dash / ry; 双 cydash = -root * ry * x1dash / rx; 双 cx = cosPhi * cxdash – sinPhi * cydash + (StartX + EndX) / 2.0; 双 cy = sinPhi * cxdash + cosPhi * cydash + (StartY + EndY) / 2.0; 双 theta1 = CalculateVectorAngle(1.0, 0.0, (x1dash – cxdash) / rx, (y1dash – cydash) / ry); double dtheta = CalculateVectorAngle((x1dash – cxdash) / rx, (y1dash – cydash) / ry, (-x1dash – cxdash) / rx, (-y1dash – cydash) / ry); if (Sweep == 0 && dtheta > 0) { dtheta -= 2.0 * Math.PI; } else if (Sweep == 1 && dtheta < 0) { dtheta += 2.0 * Math.PI; } int segments = (int)Math.Ceiling((double)Math.Abs(dtheta / (Math.PI / 2.0))); 双增量 = dtheta / 段;双 t = 8.0 / 3.0 * Math.Sin(delta / 4.0) * Math.Sin(delta / 4.0) / Math.Sin(delta / 2.0); 双startX = StartX; 双startY = StartY; 对于 (int i = 0; i < 细分市场;++i) { 双 cosTheta1 = Math.Cos(theta1); 双 sinTheta1 = Math.Sin(theta1); 双 theta2 = theta1 + delta;双 cosTheta2 = Math.Cos(theta2); 双 sinTheta2 = Math.Sin(theta2); 双端点 X = cosPhi * rx * cosTheta2 – sinPhi * ry * sinTheta2 + cx;双端点 Y = sinPhi * rx * cosTheta2 + cosPhi * ry * sinTheta2 + cy;双 dx1 = t * (-cosPhi * rx * sinTheta1 – sinPhi * ry * cosTheta1); 双 dy1 = t * (-sinPhi * rx * sinTheta1 + cosPhi * ry * cosTheta1); 双 dxe = t * (cosPhi * rx * sinTheta2 + sinPhi * ry * cosTheta2); 双染料 = t * (sinPhi * rx * sinTheta2 – cosPhi * ry * cosTheta2);点=新点[4];points[0] = new Point(startX, startY); points[1] = new Point((startX + dx1), (startY + dy1)); points[2] = new Point((endpointX + dxe), (endpointY + dye)); points[3] = new Point(endpointX, endpointY); var b = GetBezierApproximation(点,svgBezierAccuracy);对于 (int k = 1; k < b.Points.Count; k++) gcodeMoveTo(b.Points[k], “arc”); //gcodeMove(1, (float)b.Points[k].X, (float)b.Points[k].Y, 0, 0, “arc”); θ1 = θ2; startX = (float)endpointX; startY = (float)endpointY; } } private static double CalculateVectorAngle(double ux, double uy, double vx, double vy) { double ta = Math.Atan2(uy, ux); 双 tb = Math.Atan2(vy, vx); 如果 (tb >= ta) { 返回 tb – ta; } 返回 Math.PI * 2 – (ta – tb); } // 辅助函数 private static float fsqrt(float x) { return (float)Math.Sqrt(x); } private static float fvmag(float x, float y) { return fsqrt(x * x + y * y); } private static float fdistance(float x1, float y1, float x2, float y2) { return fvmag(x2-x1,y2-y1); } /// <summary> /// 计算贝塞尔线段 /// 来自 浮动 y) { 返回 fsqrt(x * x + y * y); } private static float fdistance(float x1, float y1, float x2, float y2) { return fvmag(x2-x1,y2-y1); } /// <summary> /// 计算贝塞尔线段 /// 来自 浮动 y) { 返回 fsqrt(x * x + y * y); } private static float fdistance(float x1, float y1, float x2, float y2) { return fvmag(x2-x1,y2-y1); } /// <summary> /// 计算贝塞尔线段 /// 来自http://stackoverflow.com/questions/13940983/how-to-draw-bezier-curve-by-several-points /// </summary> private static Point[] 点;private static PolyLineSegment GetBezierApproximation(Point[] controlPoints, int outputSegmentCount) { Point[] points = new Point[outputSegmentCount + 1]; 对于 (int i = 0; i <= outputSegmentCount; i++) { double t = (double)i / outputSegmentCount; points[i] = GetBezierPoint(t, controlPoints, 0, controlPoints.Length); } return new PolyLineSegment(points, true); } private static Point GetBezierPoint(double t, Point[] controlPoints, int index, int count) { if (count == 1) return controlPoints[index]; var P0 = GetBezierPoint(t, controlPoints, index, count – 1); var P1 = GetBezierPoint(t, controlPoints,
|
嗨,马丁,
一些问题:
这样的添加对您有用吗?
2. PC 板非常便宜,可以直接在线订购,而且效果比用 cnc 雕刻的要好得多。您对曲率图的考虑是什么?
3. 我最近完成了我的数控加工,我的第一次切割只是在整个切割表面上用 16 毫米的平头切割了一个 0.5 毫米的口袋。这立即解决了任何曲率问题,我有一个 100% 平坦的废纸板。
为什么你不能用这种方法解决曲率问题?
我打算进一步扩展 svg 导入以允许通过路径颜色选择工具和深度,您是否打算随时向您的项目添加工具库?
感谢您提供出色的解决方案!
亲切的问候