static internal Leg[] CreateLegs(string str, DistanceUnit entryUnit) { PathItem[] items = GetPathItems(str, entryUnit); return(CreateLegs(items)); }
/// <summary> /// Attempts to parse the supplied string /// </summary> /// <param name="str"></param> /// <param name="entryUnit">The initial default entry units</param> /// <returns>The items in the parsed path</returns> /// <exception cref="Exception">If any parsing problem is encountered</exception> static internal PathItem[] GetPathItems(string str, DistanceUnit entryUnit) { PathParser pp = new PathParser(str, entryUnit); return(pp.m_Items.ToArray()); }
void ParseWord(string str) { // Return if string is empty (could be empty if this function // has been called recursively from below). str = str.Trim(); int nc = str.Length; if (nc == 0) { return; } // If we have a new default units specification, make it // the default. There should be whitespace after the "..." if (str.Contains("...")) { DistanceUnit unit = GetUnits(str, true); PathItem item = new PathItem(PathItemType.Units, unit, 0.0); AddItem(item); return; } // If we have a counter-clockwise indicator, just remember it // and parse anything that comes after it. if (nc >= 2 && String.Compare(str.Substring(0, 2), "cc", true) == 0) { AddItem(PathItemType.CounterClockwise); ParseWord(str.Substring(2)); return; } // If we have a BC, remember it & parse anything that follows. if (str[0] == '(') { AddItem(PathItemType.BC); ParseWord(str.Substring(1)); return; } // If we have a EC, remember it & parse anything that follows. if (str[0] == ')') { AddItem(PathItemType.EC); ParseWord(str.Substring(1)); return; } // If we have a single slash character (possibly followed by // a digit or a decimal point), record the single slash & // parse anything that follows. if (str[0] == '/') { // Check for a free-standing slash, or a slash that is // followed by a numeric digit or decimal point. if (nc == 1 || Char.IsDigit(str, 1) || str[1] == '.') { AddItem(PathItemType.Slash); ParseWord(str.Substring(1)); return; } // More than one character, or what follows is not a digit. // So we are dealing with either a miss-connect, or an // omit-point. In either case, there should be whitespace // after that. if (nc == 2) { if (str[1] == '-') { AddItem(PathItemType.MissConnect); return; } if (str[1] == '*') { AddItem(PathItemType.OmitPoint); return; } } // Allow CADCOR-style data entry else if (nc == 3) { if (String.Compare(str, "/mc", true) == 0) { AddItem(PathItemType.MissConnect); return; } if (String.Compare(str, "/op", true) == 0) { AddItem(PathItemType.OmitPoint); return; } } string msg = String.Format("Unexpected qualifier '{0}'", str); throw new ApplicationException(msg); } // If we have a multiplier, it must be immediately followed // by a numeric (integer) value. if (str[0] == '*') { if (nc == 1) { throw new ApplicationException("Unexpected '*' character"); } // Pick up the repeat count (not sure if the digits need to be // followed by white space, or whether non-numeric digits are valid, // so pick up only the digits). string num = GetIntDigits(str.Substring(1)); // Error if repeat count is less than 2. int repeat; if (!Int32.TryParse(num, out repeat) || repeat < 2) { string msg = String.Format("Unexpected repeat count in '{0}'", str); throw new ApplicationException(msg); } if (repeat < 2) { string msg = String.Format("Unexpected repeat count in '{0}'", str); throw new ApplicationException(msg); } // Duplicate the last item using the repeat count. AddRepeats(repeat); // Continue parsing after the repeat count. ParseWord(str.Substring(1 + num.Length)); return; } // If the string contains an embedded qualifier (a "*" or a "/" // character), process the portion of any string prior to the // qualifier. Note that we have just handled the cases where // the qualifier was at the very start of the string. int starIndex = str.IndexOf('*'); int slashIndex = str.IndexOf('/'); if (starIndex >= 0 || slashIndex >= 0) { int qualIndex = starIndex; if (qualIndex < 0 || (slashIndex >= 0 && qualIndex > slashIndex)) { qualIndex = slashIndex; } // Process the stuff prior to the qualifier. string copy = str.Substring(0, qualIndex); ParseWord(copy); // Process the stuff, starting with the qualifier character ParseWord(str.Substring(qualIndex)); return; } // Process this string. We should have either a value or an angle. if (str.IndexOf('-') >= 0 || IsLastItemBC()) { // If the string contains a "c" character, it's a central // angle; process the string only as far as that. PathItemType type = PathItemType.Angle; int caIndex = str.ToUpper().IndexOf('C'); if (caIndex >= 0) { str = str.Substring(0, caIndex); type = PathItemType.CentralAngle; } else { // Check if it's a deflection (if so, strip out the "d"). int dIndex = str.ToUpper().IndexOf('D'); if (dIndex >= 0) { str = str.Substring(0, dIndex) + str.Substring(dIndex + 1); type = PathItemType.Deflection; } } // Try to parse an angular value into radians. double radval; if (RadianValue.TryParse(str, out radval)) { PathItem item = new PathItem(type, null, radval); AddItem(item); return; } // Bad angle. string msg = String.Format("Malformed angle '{0}'", str); throw new ApplicationException(msg); } else { // Get the current distance units. DistanceUnit unit = GetUnits(null, false); // Grab characters that look like a floating point number string num = GetDoubleDigits(str); double val; if (!Double.TryParse(num, out val)) { string msg = String.Format("Malformed value '{0}'", str); throw new ApplicationException(msg); } // If we didn't get right to the end, we may have distance units, // or the ")" character indicating an EC. if (num.Length < str.Length && str[num.Length] != ')') { unit = GetUnits(str.Substring(num.Length), false); if (unit == null) { string msg = String.Format("Malformed value '{0}'", str); throw new ApplicationException(msg); } } PathItem item = new PathItem(PathItemType.Value, unit, val); AddItem(item); if (str.Length > num.Length && str[num.Length] == ')') { ParseWord(str.Substring(num.Length)); } return; } }
/// <summary> /// Obtains a string that corresponds to the observed distances for spans on this face. /// </summary> /// <param name="defaultEntryUnit">The distance units that should be treated as the default /// (null if there is no default). /// Formatted distances that were specified using these units will not contain the units /// abbreviation. Specify null if the units should always be appended.</param> /// <returns>A data entry string corresponding to the distances for this face</returns> string GetEntryString(DistanceUnit defaultEntryUnit) { // Return if there are no observed spans. if (NumSpan == 0) { return(String.Empty); } string[] dists = new string[m_Spans.Length]; // Format each distance. for (int i = 0; i < m_Spans.Length; i++) { SpanInfo sd = m_Spans[i]; Distance d = sd.ObservedDistance; if (d == null) // is this possible? { dists[i] = String.Empty; } else { // Get the formatted distance string distString = FormatDistance(d, defaultEntryUnit); // Append any qualifiers if (sd.IsMissConnect) { distString += "/-"; } if (sd.IsOmitPoint) { distString += "/*"; } dists[i] = distString; } } // Output the first distance var str = new StringBuilder(); str.Append(dists[0]); // Output subsequent distances (with possible repeat count for unqualified spans) int numDist = (dists[0].Contains("/") ? 0 : 1); for (int i = 1; i < dists.Length; i++) { // If the current distance has a qualifier, flush out any repeat count and // the current distance (rather than something like 10*4/-, we output 10*3 10/-). // This is just to avoid potential confusion. if (dists[i].Contains("/")) { if (numDist > 1) { str.Append("*" + numDist); } str.Append(" "); str.Append(dists[i]); numDist = 0; } else { if (dists[i] == dists[i - 1]) { numDist++; } else { if (numDist > 1) { str.Append("*" + numDist); } str.Append(" "); str.Append(dists[i]); numDist = 1; } } } if (numDist > 1) { str.Append("*" + numDist); } return(str.ToString()); }