bool ParseToolScript( string s ) { int linecounter = -1; try { //_toolpaths.Clear(); //_rawElements.Clear(); //_toolpaths.Clear(); //_features.Clear(); tabWidth = eval(tbTabWidth.Text); float fRotation = eval(tbRotateDegrees.Text); PointF pRotationCenter = evalPoint(tbRotateCenter.Text); Color currentColor = Color.Green; Feature currentFeature = new Feature( FeatureType.Reference ); Dictionary<string, string> variables = new Dictionary<string, string>(); PointF pOffset = new PointF(0, 0); float fScale = 1.0f; float.TryParse(tbScale.Text, out fScale); string[] offsets = tbOffset.Text.Split(new char[] { ',' }); if (offsets.Length > 1) { pOffset.X = float.Parse(offsets[0]); pOffset.Y = float.Parse(offsets[1]); } // grab the text //string s = editor.Text; // comments: C++, C, perl // FIXME: deal with the c++ comment differently so we can match // up line numbers below (for errors) s = new Regex(@"/\*..*?\*/", RegexOptions.Singleline).Replace(s, "\r\n"); s = new Regex(@"//.*$", RegexOptions.Multiline).Replace(s, ""); s = new Regex(@"#.*$", RegexOptions.Multiline).Replace(s, ""); // split into single lines... ? s = s.Replace("\r\n", "\n"); string[] lines = s.Split(new char[] { '\n' });//, StringSplitOptions.RemoveEmptyEntries); foreach (string baseline in lines) { linecounter++; string line = baseline.Trim(); if (line.Equals("")) continue; string keyword = new Regex(@"(?:\W|\s).*$", RegexOptions.Singleline).Replace(line, "").ToUpper(); string parmstring = new Regex(@"^\S+\s+", RegexOptions.Singleline).Replace( line + " ", "").ToUpper(); foreach (string key in variables.Keys) { parmstring = new Regex(@"(?<=^|\s|\W)\$" + key + @"(?=$|\s|\W)").Replace(parmstring, variables[key]); } bool handled = false; if (keyword.Equals("SET")) { // problem: variable could be an expression. either // (1) evaluate before setting here; or (2) wrap in // parens. each is equally valid, should be no difference // in effects because we replace variables _before_ this // point. if we were replacing variables _after_ this, // then the parens would be a no brainer. // CHANGEME? for now, eval. string[] parms = parmstring.Split(new char[] { '=' }); parms[0] = parms[0].Trim().ToUpper(); float evar = eval(parms[1]); if (variables.ContainsKey(parms[0])) variables[parms[0]] = evar.ToString(); else variables.Add(parms[0], evar.ToString()); logMessage(string.Format("Set {0} = {1:0.00}", parms[0], evar )); handled = true; } if (!handled) { string[] parms = parmstring.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < parms.Length; i++) parms[i] = new Regex(@"\W").Replace(parms[i], ""); handled = true; switch (keyword) { // feature definitions case "PROFILE": if (null != currentFeature && currentFeature.Count() > 0) _features.Add(currentFeature); currentFeature = new Feature( FeatureType.Profile ); break; case "POCKET": if (null != currentFeature && currentFeature.Count() > 0) _features.Add(currentFeature); currentFeature = new Feature( FeatureType.Pocket | FeatureType.Shadowfill ); break; case "TRACE": if (null != currentFeature && currentFeature.Count() > 0) _features.Add(currentFeature); currentFeature = new Feature( FeatureType.Trace ); break; case "REFERENCE": if (null != currentFeature && currentFeature.Count() > 0) _features.Add(currentFeature); currentFeature = new Feature( FeatureType.Reference ); break; // option case "COLOR": // feature color, just for painting currentColor = System.Drawing.ColorTranslator.FromHtml(parms[0]); break; default: handled = false; break; } if (handled) { foreach (string p in parms) { if (p.Equals("DOUBLE")) currentFeature.featureType |= FeatureType.Double; if (p.Equals("INSIDE")) currentFeature.featureType |= FeatureType.Inside; if (p.Equals("DOGBONE") || p.Equals("BONE")) currentFeature.featureType |= FeatureType.Dogbone; //if (p.Equals("SHADOWFILL") || p.Equals("SHADOW")) currentFeature.featureType |= FeatureType.Shadowfill; if (p.Equals("POLYGONFILL") || p.Equals("POLYFILL")) currentFeature.featureType &= ~FeatureType.Shadowfill; if (p.Equals("TAB") || p.Equals("TABS")) currentFeature.featureType |= FeatureType.Tabs; } //logMessage("Feature: " + currentFeature.featureType); } } if (!handled) { string[] parms = parmstring.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); // math ops on all parms [ FIXME: use named parms? ] float[] fparms = new float[parms.Length]; for (int i = 0; i < parms.Length; i++) { //parms[i] = new DataTable().Compute(parms[i], null).ToString(); //fparms[i] = float.Parse(parms[i].Trim()); fparms[i] = eval(parms[i]); } int tabs = 0; //ToolpathElement elt = null; List<ToolpathElement> elts = new List<ToolpathElement>(); switch (keyword) { // global config options case "OFFSET": // reset offset pOffset = new PointF(fparms[0], fparms[1]); break; case "ROTATE": // rotation, degrees fRotation = fparms[0]; break; case "CENTER": // rotation center pRotationCenter = new PointF(fparms[0], fparms[1]); break; case "SCALE": // reset scale fScale = fparms[0]; break; // feature options case "DEPTH": // depth from top currentFeature.Depth = fparms[0]; break; case "START": // depth from top to _START_ cutting, if not default currentFeature.Start = fparms[0]; break; // basic types case "ARC": // center.x, center.y, diameter, start, end elts.Add(new Arc(new PointF(fparms[0], fparms[1]), fparms[2], -1, fparms[3], fparms[4])); break; case "ARC2": // center.x, center.y, diameter, diameter2, start, end elts.Add(new Arc(new PointF(fparms[0], fparms[1]), fparms[2], fparms[3], fparms[4], fparms[5])); break; case "CIRCLE": // center.x, center.y, diameter Arc circle = new Arc(new PointF(fparms[0], fparms[1]), fparms[2]); //if (fparms.Length > 3) circle.Tab = true; elts.Add(circle); break; case "LINE": // start.x, start.y, end.x, end.y elts.Add(new Line(new PointF(fparms[0], fparms[1]), new PointF(fparms[2], fparms[3]))); break; /* case "TAB": // start.x, start.y, end.x, end.y ToolpathElement elt = (new Line(new PointF(fparms[0], fparms[1]), new PointF(fparms[2], fparms[3]))); elt.Tab = true; elts.Add(elt); break; */ // convenience types case "RECT": // origin.x, origin.y, width, height, [tabs] elts.Add(new Line(new PointF(fparms[0], fparms[1]), new PointF(fparms[0], fparms[1] + fparms[3]))); elts.Add(new Line(new PointF(fparms[0] + fparms[2], fparms[1]), new PointF(fparms[0] + fparms[2], fparms[1] + fparms[3]))); elts.Add(new Line(new PointF(fparms[0], fparms[1]), new PointF(fparms[0] + fparms[2], fparms[1]))); elts.Add(new Line(new PointF(fparms[0], fparms[1] + fparms[3]), new PointF(fparms[0] + fparms[2], fparms[1] + fparms[3]))); /* if (fparms.Length > 4) { int flags = (int)fparms[4]; if ((flags & 0x01) != 0) elts[0].Tab = true; if ((flags & 0x02) != 0) elts[1].Tab = true; if ((flags & 0x04) != 0) elts[2].Tab = true; if ((flags & 0x08) != 0) elts[3].Tab = true; } */ break; case "ROUNDRECT": // origin.x, origin.y, width, height, diameter, [tabs] float r = fparms[4] / 2.0f; // edges elts.Add(new Line(new PointF(fparms[0], fparms[1] + r), new PointF(fparms[0], fparms[1] + fparms[3] - r))); elts.Add(new Line(new PointF(fparms[0] + fparms[2], fparms[1] + r), new PointF(fparms[0] + fparms[2], fparms[1] + fparms[3] - r))); elts.Add(new Line(new PointF(fparms[0] + r, fparms[1]), new PointF(fparms[0] + fparms[2] - r, fparms[1]))); elts.Add(new Line(new PointF(fparms[0] + r, fparms[1] + fparms[3]), new PointF(fparms[0] + fparms[2] - r, fparms[1] + fparms[3]))); // round corners elts.Add(new Arc(new PointF(fparms[0] + r, fparms[1] + fparms[3] - r), fparms[4], -1, 180, 270)); elts.Add(new Arc(new PointF(fparms[0] + fparms[2] - r, fparms[1] + fparms[3] - r), fparms[4], -1, 270, 360)); elts.Add(new Arc(new PointF(fparms[0] + fparms[2] - r, fparms[1] + r), fparms[4], -1, 0, 90)); elts.Add(new Arc(new PointF(fparms[0] + r, fparms[1] + r), fparms[4], -1, 90, 180)); /* if (fparms.Length > 5) { int flags = (int)fparms[5]; if ((flags & 0x01) != 0) elts[0].Tab = true; if ((flags & 0x02) != 0) elts[1].Tab = true; if ((flags & 0x04) != 0) elts[2].Tab = true; if ((flags & 0x08) != 0) elts[3].Tab = true; } */ break; } foreach (ToolpathElement elt in elts) { // add any translation/scale ToolpathElement tp = elt.Clone(); // set color... tp.color = currentColor; if (fRotation != 0) tp = tp.Rotate(fRotation, pRotationCenter); currentFeature.Add(tp.Scale(fScale).Offset(pOffset)); //logMessage("Path element: " + elt.elementType); } } } linecounter = -1; if (null != currentFeature && currentFeature.Count() > 0 ) _features.Add(currentFeature); int elementCount = 0; foreach (Feature feature in _features) { elementCount += feature.Count(); } Invoke( new Action<string>(( str ) => { statusMessage.Text = str; }), new object[]{ string.Format( "Parse OK: {0} element{1} in {2} feature{3}", elementCount, elementCount == 1 ? "" : "s", _features.Count(), _features.Count() == 1 ? "" : "s" ) }); } catch (Exception e) { if (linecounter >= 0) { logMessage("Parse error on script line " + linecounter); Invoke(new Action<int>((line) => { highlightCodeError( line ); }), new object[] { linecounter }); } logMessage(e.Message); logMessage(e.StackTrace); Invoke(new Action<string>((str) => { statusMessage.Text = str; ctc.SelectedIndex = 0; }), new object[] { "Parse error, see log" }); return false; } return true; }