using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Windows.Forms; using System.Text; using System.Drawing; using System.Text.RegularExpressions; using VG; namespace XYPlots { /// /// Summary description for XYPlot. /// public class XYPlot { #region Log4Net // C2018-035 Added error Handling to provide more useful information when a plot fails private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); #endregion static string _MyFontFamily = "Letter Gothic Tall"; public static string MyFontFamily { get { return _MyFontFamily; } set { _MyFontFamily = value; } } private static Color _BlackColor = Color.Red; public static Color BlackColor { get { return VG.VG.BlackColor; } set { VG.VG.BlackColor = value; } } public float Width { get { return 72 * (LeftMargin + RightMargin) + printerunits[0] * .05F; } } public float Height { get { return 72 * (TopMargin + BottomMargin) + printerunits[1] * .05F; } } public float PlotWidth { get { return (float) userunits[X]; } } public float PlotHeight { get { return (float) userunits[Y]; } } private double ConvertToTwips = 4.8; static int MAX_XY_STACK = 8; /* this is max of CIE cursor/font stack */ static int DPI = 1440; //300; static int CWIDEDOTS = 120; //25; static int CHIGHDOTS = 240; //50; static int STRAIGHT = 0; static int CURVE = 1; static int X = 0; static int Y = 1; static int Dimensions = 2; static int USER = 0; static int PLOT = 1; static double PI = 3.141592653; static double Zero = 0.0; static double ANGLELIMIT = 1.0; // !!!! NEED REAL SUPERSCRIPT ON/OFF TOKENS static string[] SuperScript = { "##", "##" }; static string[] SubScript = { "~~", "~~" }; FileStream XYPlotFile; private int[] SavedX; private int[] SavedY; private int stack; /// /// Set All Margins at once /// /// Left Margin in Inches. /// Top Margin in Inches. /// Right Margin in Inches. /// Bottom Margin in Inches. public void SetMargins(float leftMargin, float topMargin, float rightMargin, float bottomMargin) { _LeftMargin = leftMargin * 1440; _TopMargin = yTopMarginAdjust + topMargin * 1440; _RightMargin = rightMargin * 1440; _BottomMargin = bottomMargin * 1440; } private float _LeftMargin = 1440; /// /// Left Margin in Inches. /// public float LeftMargin { get { return _LeftMargin / 1440; } set { _LeftMargin = value * 1440; } } private float _RightMargin = 720; /// /// Right Margin in Inches. /// public float RightMargin { get { return _RightMargin / 1440; } set { _RightMargin = value * 1440; } } private float _TopMargin = 1440; /// /// Top Margin in Inches. /// public float TopMargin { get { return _TopMargin / 1440; } set { _TopMargin = value * 1440; } } private float _BottomMargin = 1440; /// /// Bottom Margin in Inches. /// public float BottomMargin { get { return _BottomMargin / 1440; } set { _BottomMargin = value * 1440; } } public int LinesUsed; private string valuestring; private string powerstring; private int GridOnFlag, Visible, ShadowFlag; private char[] type = new char[Dimensions]; private double FontPitch = 10.0; private double[] minimum = new double[Dimensions]; private double[] maximum = new double[Dimensions]; private double[] userunits = new double[Dimensions]; private int[] printerunits = new int[Dimensions]; private int[] Position = new int[Dimensions]; private double[,] Scale = new double[2, Dimensions]; private double[,] Offset = new double[2, Dimensions]; private double[] delta = new double[Dimensions]; private int[] cycles = new int[Dimensions]; private int[] onecycle = new int[Dimensions]; private int[] minor = new int[Dimensions]; private int[] spcminor = new int[Dimensions]; private string[] AxisTitles = new string[Dimensions]; private int[] AxisLabel = new int[Dimensions];// 1 for YES(default), 0 for NO private int CurPenWidth, DrawDirection, LineFlag, LineDiv; private int EndFlag = 0; public string Buff; private int BuffPtr = 0; private bool[,] doLOG10 = { { false, false }, { false, false } }; public struct point { public int[] xyValue; //new int[Dimensions]; } public struct XyBox { public int Shadow; public string BoxText; public point BoxMinimum; public point BoxMaximum; }; public class XyBoxes : List { } private XyBoxes AllBoxes = new XyBoxes(); private XyBoxes ActiveBoxes = new XyBoxes(); public class DataPoint { public override string ToString() // Make it easier to Debug { return string.Format("{0},{1}", APoint.xyValue[X],APoint.xyValue[Y]); } private point m_APoint; public point APoint { get { return m_APoint; } set { m_APoint = value; } } private double m_slope; // slope of tangent to circle at this point public double slope { get { return m_slope; } set { m_slope = value; } } } public class DataPoints : List { } public struct PlotLine { public int PlotType; public int PlotDivisions; public DataPoints PlotDataPoints; }; private List AllPlots = new List(); private int YLandScape = 0; /* y axis title is horizontal */ private point YTitleOrigin; /* y axis title origin if vertical */ private double FixAngle(double a1) { double retval; int sign; if (a1 < 0) { a1 = -a1; sign = -1; } else sign = 1; retval = sign * Math.Floor(0.5 + a1); return retval; } private double dsquare(int val) { double result; result = (double)(val * val); return result; } private double FMin(double f1, double f2) { return ((f1 >= f2) ? f2 : f1); } private double FMax(double f1, double f2) { return ((f1 >= f2) ? f1 : f2); } private double atan_deg(double x) { return (Math.Atan(x) * 180.0 / PI); } private double cos_deg(double x) { return (Math.Cos(x * PI / 180.0)); } private double tan_deg(double x) { return (Math.Tan(x * PI / 180.0)); } private double sin_deg(double x) { return (Math.Sin(x * PI / 180.0)); } /// /// the following function is pointed to by a function pointer /// and is provided for compatibility with log10() function usage /// /// /// private double linear(double x) { return x; } private bool isWhiteSpace(char cptr) { bool rtnval = false; if (!cptr.Equals(null)) { int idx = "\t\n\r\f ".IndexOf(cptr); rtnval = (idx > -1); } return rtnval; } private string NextPiece() { string rtnval; int ptr; while (BuffPtr >= 0 && Buff[BuffPtr] != 0 && isWhiteSpace(Buff[BuffPtr])) BuffPtr++; ptr = BuffPtr; while (BuffPtr >= 0 && Buff[BuffPtr] != 0 && !isWhiteSpace(Buff[BuffPtr])) BuffPtr++; if (EndOfCommand()) EndFlag = 1; rtnval = Buff.Substring(ptr, BuffPtr - ptr); BuffPtr++; return rtnval; } private bool EndOfCommand() { int tmpPtr = BuffPtr; while (!Buff[tmpPtr].Equals('\0') && Buff[tmpPtr].Equals(' ')) tmpPtr++; if (!Buff[tmpPtr].Equals('\0') && !isWhiteSpace(Buff[tmpPtr])) return false; else if (Buff[tmpPtr] == '\r' || Buff[tmpPtr] == '\n' || Buff[tmpPtr] == '\0') return true; else return false; } private bool LoadBuff(string FileName) { if (!File.Exists(FileName)) { // File does not exist, show error message MessageBox.Show(String.Format("X/Y Plot File {0} Does Not Exist", FileName), "Error Opening X/Y Plot File"); return false; } // Open the X/Y Plot file try { XYPlotFile = File.OpenRead(FileName); } catch (Exception e) { // cannot open the x/y plot file MessageBox.Show(e.Message, String.Format("Error Opening {0} for Reading", FileName)); return false; } int blen = (int)XYPlotFile.Length; int bread = 0; // initialize a byte array to read into byte[] bbuf = new byte[blen + 1]; for (int i = 0; i < blen; i++) bbuf[i] = 0; // Read the contents of the x/y plot file into the byte array try { bread = XYPlotFile.Read(bbuf, 0, blen); } catch (Exception e) { MessageBox.Show(e.Message, String.Format("Error Reading {0}", FileName)); return false; } try { XYPlotFile.Close(); } catch (Exception e) { MessageBox.Show(e.Message, String.Format("Error Closing {0}", FileName)); return false; } StringBuilder sb = new StringBuilder(); for (int i = 0; i < bbuf.Length; i++) { if (bbuf[i] == '\r' && bbuf[i - 1] == ' ') sb.Remove(i - 1, 1); sb.Append(Convert.ToChar(bbuf[i])); } Buff = sb.ToString(); BuffPtr = 0; return true; } private void LoadBuffFromString(string str) { Buff = str; } private int getint() { int retval; string np = NextPiece(); np = Regex.Replace(np, "[^-0-9]", ""); retval = Convert.ToInt32(np, 10); return retval; } // A 'special' isWhiteSpaceDelta, NextPieceDelta, and getdoubleDelta was added because Wolf Creek // has a ',' between the x/y delta of one of their plots (C-1). // this was causing the x delta to be set to 50,250. private bool isWhiteSpaceDelta(char cptr) { bool rtnval = false; if (!cptr.Equals(null)) { int idx = "\t\n\r\f ,".IndexOf(cptr); rtnval = (idx > -1); } return rtnval; } private string NextPieceDelta() { string rtnval; int ptr; while (BuffPtr >= 0 && Buff[BuffPtr] != 0 && isWhiteSpaceDelta(Buff[BuffPtr])) BuffPtr++; ptr = BuffPtr; while (BuffPtr >= 0 && Buff[BuffPtr] != 0 && !isWhiteSpaceDelta(Buff[BuffPtr])) BuffPtr++; if (EndOfCommand()) EndFlag = 1; rtnval = Buff.Substring(ptr, BuffPtr - ptr); BuffPtr++; return rtnval; } private double getdoubleDelta() { double retval; retval = Convert.ToDouble(NextPieceDelta()); return retval; } private double getdouble() { double retval; retval = Convert.ToDouble(NextPiece()); return retval; } private char NextChar() { return Buff[BuffPtr++]; } private char getchr() { string nxtstring = NextPiece(); if (nxtstring.Equals("")) return '\0'; else return nxtstring[0]; } // C2018-035 Added error Handling to provide more useful information when a plot fails private string _XYPlotIssue; public string XYPlotIssue { get { return _XYPlotIssue; } set { _XYPlotIssue = value; } } private point GetPair(int flag) { point retval = new point(); retval.xyValue = new int[Dimensions]; double x, y; char[] sepchar = { ',' }; string nextPiece = NextPiece(); // Plot Definition string[] xystr = nextPiece.Split(sepchar); // C2018-035 Added error Handling to provide more useful information when a plot fails if (xystr.Length != 2) XYPlotIssue = String.Format("Invalid Pair {0}", nextPiece); if (xystr.Length == 1) throw new Exception(XYPlotIssue); x = double.Parse(xystr[0]); char[] trimEndDot = { '.' }; // Wolf Creek OFN SB-008, figure 3 had a string like 50.0. so trim the ending '.' string ystr = xystr[1]; if (ystr.EndsWith(".0")) // bug fix B2012-169, the Trim converted a ".75" value to a "75.0" value ystr = ystr.Trim(trimEndDot); // count the number of '.', if there are two and the last char is a '.', trim it (this was causing // a crash in CAL-OTO-OTO-BG-00001. This was done this way so as to be very specific to the // problem found in Callaway, i.e. didn't want to break something else. int cnt = 0; int indx = ystr.IndexOf("."); while (indx >= 0) { cnt++; indx = indx+1==ystr.Length?-1:ystr.IndexOf(".", indx + 1); } if (cnt > 1) ystr = ystr.TrimEnd(trimEndDot); y = double.Parse(ystr); if (doLOG10[flag, X]) retval.xyValue[X] = (int)(Offset[flag, X] + Scale[flag, X] * Math.Log10(x) + .5); else retval.xyValue[X] = (int)(Offset[flag, X] + Scale[flag, X] * x + .5); if (doLOG10[flag, Y]) retval.xyValue[Y] = (int)(printerunits[Y] - (Offset[flag, Y] + Scale[flag, Y] * Math.Log10(y) + .5)); else retval.xyValue[Y] = (int)(printerunits[Y] - (Offset[flag, Y] + Scale[flag, Y] * y + .5)); return (retval); } private string GetString() { char retval; StringBuilder Lbuff = new StringBuilder(); retval = NextChar(); if (retval != '"' && retval != '\x1C') // open double quote MessageBox.Show("Double Quote not found", "Syntax problem in XY Plot"); retval = NextChar(); while (retval != 0 && retval != '\n') { switch (retval) { case '"': case '\x1D': // close double quote retval = NextChar(); if (retval == ' ') { Lbuff.Append('\n'); retval = NextChar(); retval = NextChar(); } break; case '\r': retval = NextChar(); break; case '\\': retval = NextChar(); /*always take next*/ Lbuff.Append(retval); retval = NextChar(); break; default: Lbuff.Append(retval); retval = NextChar(); break; } } return Lbuff.ToString(); } private void FixBuffIfNeeded() { int ptr = 0; Buff = Buff.Trim(" \r\n".ToCharArray()); while (Buff.Contains("> ")) Buff = Buff.Replace("> ", ">"); if (Buff.StartsWith("<< //Buff = Regex.Replace(Buff, @"[ ]+<", "<"); Buff = Buff.Replace(">\r ", ">\r\n "); Buff = Regex.Replace(Buff, @"[ ]+<", "<"); // some data only had carriage return, replace these with cr/nl so that following code // will work Buff = Buff.Replace(">\r<", ">\r\n<"); Buff = Buff.Replace("><", ">\r\n<"); // some data had cr/cr/nl, change to cr/nl Buff = Buff.Replace("\r\r\n", "\r\n"); while ((ptr = Buff.IndexOf(">\r\n<", ptr)) > 0) { // blank out ">" Buff = Buff.Remove(ptr, 1); Buff = Buff.Insert(ptr, " "); // remove "<" Buff = Buff.Remove(ptr + 3, 1); // if command on next line is blank, // combine with the previous line if (Buff[ptr + 3] == ' ') Buff = Buff.Remove(ptr, 3); } ptr = Buff.Length - 5; // back up past >>\r\n if (Buff.IndexOf(">>\r\n", ptr) > 0) { Buff = Buff.Remove(ptr, 2); Buff = Buff.Insert(ptr, " "); } else if (Buff.EndsWith(">>")) // doesn't end with return chars... Buff = Buff.Substring(0, Buff.Length - 2) + " \r\n\0x00"; // needs to end with null else if (Buff.EndsWith(">")) // doesn't end with return chars... Buff = Buff.Substring(0, Buff.Length - 1) + " \r\n\0x00"; // needs to end with null Buff = Regex.Replace(Buff, @"([0-9])\r\n([0-9])", "$1 $2"); } private void CloseGraph() { /* Send back number of lines used assuming 6 lines per inch */ if (LinesUsed == 0) LinesUsed = (int)(1.5 * CHIGHDOTS); /* adjust for x axis tics */ LinesUsed += printerunits[Y]; LinesUsed = LinesUsed / CHIGHDOTS; } private void GetScaleInfo() { GridOnFlag = getint(); userunits[X] = getdouble(); userunits[Y] = getdouble(); printerunits[X] = (int)(DPI * userunits[X]); printerunits[Y] = (int)(DPI * userunits[Y]); minimum[X] = getdouble(); maximum[X] = getdouble(); minimum[Y] = getdouble(); maximum[Y] = getdouble(); type[X] = getchr(); type[Y] = getchr(); if (EndFlag == 0) delta[X] = getdoubleDelta(); if (EndFlag == 0) delta[Y] = getdoubleDelta(); if (EndFlag == 0) spcminor[X] = getint(); if (EndFlag == 0) spcminor[Y] = getint(); Offset[USER, X] = 0; Offset[USER, Y] = 0; Scale[USER, X] = DPI; Scale[USER, Y] = DPI; /* in the following if blocks, the array variable f is a function pointer which is set to either the function linear or log10. */ /* X-axis function generation and scaling */ if (type[X] != 'L') { // Linear doLOG10[PLOT, X] = false; LinearScale(X); Scale[PLOT, X] = printerunits[X] / (maximum[X] - minimum[X]); Offset[PLOT, X] = -Scale[PLOT, X] * minimum[X]; } else { // Log10 doLOG10[PLOT, X] = true; LogScale(X); Scale[PLOT, X] = printerunits[X] / (Math.Log10(maximum[X]) - Math.Log10(minimum[X])); Offset[PLOT, X] = -Scale[PLOT, X] * Math.Log10(minimum[X]); } /* Y-axis function generation and scaling */ if (type[Y] != 'L') { // Linear doLOG10[PLOT, Y] = false; LinearScale(Y); Scale[PLOT, Y] = printerunits[Y] / (maximum[Y] - minimum[Y]); Offset[PLOT, Y] = -Scale[PLOT, Y] * minimum[Y]; } else { // Log10 doLOG10[PLOT, Y] = true; LogScale(Y); Scale[PLOT, Y] = printerunits[Y] / (Math.Log10(maximum[Y]) - Math.Log10(minimum[Y])); Offset[PLOT, Y] = -Scale[PLOT, Y] * Math.Log10(minimum[Y]); } } private void GetAxisTitle(int flag) { AxisTitles[flag] = GetString(); } private string stripSuperSub(string instr) { StringBuilder sb = new StringBuilder(instr); sb.Replace(SuperScript[0], ""); sb.Replace(SuperScript[1], ""); sb.Replace(SubScript[0], ""); sb.Replace(SubScript[1], ""); return sb.ToString(); } private point DetermineBoxMax(XyBox boxptr) { point newval = new point(); newval.xyValue = new int[Dimensions]; string tmp; int pos = 0, prevPos = 0; int nl = 0, xmax = 0, ilen = 0; tmp = stripSuperSub(boxptr.BoxText); tmp = tmp.Replace("\r\n", "\n"); while ((pos = tmp.IndexOf('\n', pos)) > -1) { ilen = pos - prevPos; xmax = Math.Max(xmax, ilen); // OLD: prevPos = pos; prevPos = pos + 1; pos++; nl++; } // OLD: ilen = tmp.Substring(prevPos + 1).Length; ilen = tmp.Length - prevPos; // tmp.Substring(prevPos).Length; xmax = Math.Max(xmax, ilen) + 2; newval.xyValue[X] = boxptr.BoxMinimum.xyValue[X] + (xmax * CWIDEDOTS); // OLD: newval.xyValue[Y] = boxptr.BoxMinimum.xyValue[Y] - (nl * CHIGHDOTS) - (int)(30 * ConvertToTwips); newval.xyValue[Y] = boxptr.BoxMinimum.xyValue[Y] - (nl * CHIGHDOTS) - (int)(19 * ConvertToTwips); return newval; } private float yTopMarginAdjust = 0; private void GetBoxParameters() { XyBox NewBox = new XyBox(); point Origin; Origin = GetPair(USER); string str = GetString(); NewBox.BoxText = str; NewBox.BoxMinimum = Origin; NewBox.Shadow = ShadowFlag; ShadowFlag = 0; NewBox.BoxMaximum = DetermineBoxMax(NewBox); point minPoint = new point(); minPoint.xyValue = new int[Dimensions]; point maxPoint = new point(); maxPoint.xyValue = new int[Dimensions]; minPoint.xyValue[X] = Origin.xyValue[X]; minPoint.xyValue[Y] = NewBox.BoxMaximum.xyValue[Y]; maxPoint.xyValue[X] = NewBox.BoxMaximum.xyValue[X]; maxPoint.xyValue[Y] = Origin.xyValue[Y]; NewBox.BoxMinimum = minPoint; if (minPoint.xyValue[Y] < 0) // If the box is above the range of the Plot then the top margin must be adjusted // so that the text is visible yTopMarginAdjust = -(minPoint.xyValue[Y]+720); // TopMargin defaults to .5 Inches (720 Twips) NewBox.BoxMaximum = maxPoint; AllBoxes.Add(NewBox); } private void GetLineParameters() { DataPoints dataPoints = new DataPoints(); int pointcount; pointcount = EndFlag = 0; while (EndFlag == 0) { DataPoint pl = new DataPoint(); pl.APoint = new point(); pl.APoint = GetPair(PLOT); pointcount++; dataPoints.Add(pl); } if (LineFlag == CURVE && pointcount > 2) CalculateSlopes(dataPoints); else LineFlag = STRAIGHT; //#if DEBUG //ShowPoints(dataPoints); //#endif AddAPlot(dataPoints); } private double FindSlope(point first, point last) { double dx, dy, result; dx = last.xyValue[X] - first.xyValue[X]; dy = (last.xyValue[Y] - first.xyValue[Y]); if (dx == 0.0) { if (dy > 0) result = Convert.ToDouble("1.E99"); else result = Convert.ToDouble("-1.E99"); } else result = dy / dx; return result; } private double FindEndSlope(point first, point last, double s1) { double result; result = 2.0 * FindSlope(first, last) - s1; if (result * s1 < 0.0) result = 0.0; return result; } private void CalculateSlopes(DataPoints dataPoints) { DataPoint thispt, prevpt, firstpt; long yval, y1, y3; int PlAryIdx = 0; int PlAryNumItems = dataPoints.Count; prevpt = dataPoints[PlAryIdx]; PlAryIdx++; thispt = dataPoints[PlAryIdx]; while (PlAryIdx + 1 < dataPoints.Count) { thispt.slope = Zero; yval = thispt.APoint.xyValue[Y]; y1 = prevpt.APoint.xyValue[Y]; y3 = dataPoints[PlAryIdx + 1].APoint.xyValue[Y]; if ((yval - y1) * (y3 - yval) > 0) thispt.slope = FindSlope(prevpt.APoint, dataPoints[PlAryIdx + 1].APoint); prevpt = thispt; PlAryIdx++; thispt = dataPoints[PlAryIdx]; } firstpt = dataPoints[0]; firstpt.slope = FindEndSlope(firstpt.APoint, dataPoints[1].APoint, dataPoints[1].slope); thispt.slope = FindEndSlope(thispt.APoint, prevpt.APoint, prevpt.slope); } private void AddAPlot(DataPoints ptr) { PlotLine NewLine = new PlotLine(); NewLine.PlotType = LineFlag; NewLine.PlotDivisions = LineDiv; NewLine.PlotDataPoints = ptr; AllPlots.Insert(0, NewLine); } private void GenerateGrid(VG.Page pg, IVGOutput vgOutput) { ActiveBoxes.Clear(); Position[X] = 0; Position[Y] = 0; // printerunits[Y]; SavePosition(); SetPenDiameter(5); BoxRelative(printerunits[X], printerunits[Y], CurPenWidth, pg, vgOutput); if (GridOnFlag == 0) Visible = 0; //if (vgOutput is VGOut_Graphics) //{ DoGrid(X, pg, vgOutput, 1); DoGrid(Y, pg, vgOutput, 1); DoGrid(X, pg, vgOutput, 2); DoGrid(Y, pg, vgOutput, 2); DoGrid(X, pg, vgOutput, 3); DoGrid(Y, pg, vgOutput, 3); //} //else if (vgOutput is VGOut_C1PDF) //{ // DrawDirection = Y; // DoGrid(X, pg, vgOutput); // DrawDirection = X; // DoGrid(Y, pg, vgOutput); //} Visible = 1; RecallPosition(); // Draw outline last to overlap any grid lines. //SetPenDiameter(5); //BoxRelative(printerunits[X], printerunits[Y], CurPenWidth, pg, vgOutput); } private void DoGrid(int flag, VG.Page pg, IVGOutput vgOutput) { if (type[flag] != 'L') DoLinearGrid(flag, pg, vgOutput); else DoLogGrid(flag, pg, vgOutput); } private void DoLinearGrid(int flag, VG.Page pg, IVGOutput vgOutput) { int i, n, ns, subminor; int ptval; n = (int)(0.5 + (maximum[flag] - minimum[flag]) / delta[flag]); ns = n * minor[flag]; if ((minor[flag] % 2) != 0) subminor = minor[flag]; else subminor = minor[flag] / 2; for (i = 0; i <= ns; i++) { SetPenDiameter((((i % minor[flag]) != 0) ? (((i % subminor) != 0) ? 1 : 2) : 3)); ptval = ((int)printerunits[flag]) * i / ns; if (flag == Y) ptval = printerunits[Y] - ptval; MoveAbsolute(((flag == X) ? ptval : 0), ((flag == Y) ? ptval : 0)); if (i % minor[flag] == 0) WriteValue(flag, minimum[flag] + i * delta[flag] / minor[flag], false, pg, vgOutput); DrawGridLine((flag == 0) ? 1 : 0, ptval, pg, vgOutput); } } private void DoGrid(int flag, VG.Page pg, IVGOutput vgOutput, int gridPen) { DrawDirection = 1 - flag; if (type[flag] != 'L') DoLinearGrid(flag, pg, vgOutput, gridPen); else if (gridPen == 3) DoLogGrid(flag, pg, vgOutput); } private void DoLinearGrid(int flag, VG.Page pg, IVGOutput vgOutput, int gridPen) { int i, n, ns, subminor; int ptval; n = (int)(0.5 + (maximum[flag] - minimum[flag]) / delta[flag]); ns = n * minor[flag]; if ((minor[flag] % 2) != 0) subminor = minor[flag]; else subminor = minor[flag] / 2; for (i = 0; i <= ns; i++) { int pd = (((i % minor[flag]) != 0) ? (((i % subminor) != 0) ? 1 : 2) : 3); if (pd == gridPen) { SetPenDiameter(pd); ptval = ((int)printerunits[flag]) * i / ns; if (flag == Y) ptval = printerunits[Y] - ptval; MoveAbsolute(((flag == X) ? ptval : 0), ((flag == Y) ? ptval : 0)); if (i % minor[flag] == 0) WriteValue(flag, minimum[flag] + i * delta[flag] / minor[flag], false, pg, vgOutput); DrawGridLine((flag == 0) ? 1 : 0, ptval, pg, vgOutput); } } } private void DoLogGrid(int flag, VG.Page pg, IVGOutput vgOutput) { double showval; int gs, ge, gd; int i, ptval; showval = minimum[flag]; for (i = 0; i < cycles[flag]; i++) { gs = gd = 100; ge = 1000; ptval = ((int)printerunits[flag]) * i / cycles[flag]; if (flag == Y) ptval = printerunits[Y] - ptval; //jj MoveAbsolute(((flag == X) ? ptval : 0), ((flag == Y) ? ptval : 0)); SetPenDiameter(3); WriteValue(flag, showval, false, pg, vgOutput); GenGrid(flag, gs, ge, gd, onecycle[flag], 2, i * onecycle[flag], pg, vgOutput); showval *= 10.0; } ptval = ((int)printerunits[flag]) * i / cycles[flag]; if (flag == Y) ptval = printerunits[Y] - ptval; //jj MoveAbsolute(((flag == X) ? ptval : 0), ((flag == Y) ? ptval : 0)); SetPenDiameter(3); WriteValue(flag, showval, false, pg, vgOutput); } private void WriteValue(int flag, double val, bool SubLogValue, VG.Page pg, IVGOutput vgOutput) { int size; size = GenNumberString(val); SavePosition(); if (flag == X) { MoveRelative(0, -printerunits[Y]); if (!SubLogValue) DrawGridRelative(0, (int)(-30 * ConvertToTwips), pg, vgOutput); // OLD: MoveRelative((int)((-130 * size / (int)FontPitch) * ConvertToTwips), (int)(-60 * ConvertToTwips)); MoveRelative((int)((2 - 130 * size / (int)FontPitch) * ConvertToTwips), (int)(-62 * ConvertToTwips)); if ((AxisLabel[0]) != 0) { if (SubLogValue) { StringBuilder sb = new StringBuilder(); sb.Append(SuperScript[0]); sb.Append(valuestring); sb.Append(SuperScript[1]); valuestring = sb.ToString(); MoveRelative(30, 30); } GraphText(valuestring, pg, vgOutput); } } else { if (!SubLogValue) DrawGridRelative((int)(-30 * ConvertToTwips), 0, pg, vgOutput); // OLD: MoveRelative((int)(-(15 + 300 * size / (int)FontPitch) * ConvertToTwips), (int)(-15 * ConvertToTwips)); MoveRelative((int)(-(14 + 250 * size / (int)FontPitch) * ConvertToTwips), (int)(-16 * ConvertToTwips)); if ((AxisLabel[1]) != 0) { if (SubLogValue) { StringBuilder sb = new StringBuilder(); sb.Append(SuperScript[0]); sb.Append(valuestring); sb.Append(SuperScript[1]); valuestring = sb.ToString(); MoveRelative(90, -90); //jj } GraphText(valuestring, pg, vgOutput); } } RecallPosition(); } private int GenNumberString(double x) { int power, size, sign; double mantissa; if (x == 0.0) return (savenumber(x)); if (x < 0.0) { x = -x; sign = 1; } else sign = 0; mantissa = Math.Log10(x); power = 0; while (mantissa < 0.999) { power--; mantissa++; } while (mantissa >= 0.999) { power++; mantissa--; } if (mantissa < 0) mantissa = 0; if (power > -5 && power < 5) size = savenumber(x); else { size = savenumber(Math.Pow(10.0, mantissa)); size += addpower(power); if (valuestring.StartsWith("1x")) { size -= 2; valuestring = valuestring.Remove(0, 2); } } if (sign != 0) { valuestring = "-" + valuestring; size++; } return (size); } private int savenumber(double x) { valuestring = x.ToString("G"); return valuestring.Length; } private int addpower(int i) { int tlen; powerstring = string.Format("x10{0}{1}{2}", SuperScript[0], i.ToString(), SuperScript[1]); valuestring = valuestring + powerstring; tlen = SuperScript[0].Length + SuperScript[1].Length; return (powerstring.Length - tlen); } private void DoAxisTitles(VG.Page pg, IVGOutput vgOutput) { int len, frommargin; string str; SavePosition(); if ((AxisTitles[X] != null) && (len = AxisTitles[X].Length) > 0) { frommargin = (int)((0.5 * (printerunits[X])) - (0.47 * (len * CWIDEDOTS))); // OLD: frommargin = (int)((0.5 * (printerunits[X])) - (0.5 * (len * CWIDEDOTS))); MoveAbsolute(frommargin, (3 * CHIGHDOTS) + printerunits[Y]); PrintText(AxisTitles[X], pg, vgOutput); LinesUsed += (3 * CHIGHDOTS); AxisTitles[X] = null; } if ((AxisTitles[Y] != null) && (len = AxisTitles[Y].Length) > 0) { if (YLandScape > 0) { int strIdx = 0; MoveTo(YTitleOrigin); str = AxisTitles[Y]; while (strIdx < str.Length) { PrintText(str[strIdx].ToString(), pg, vgOutput); MoveRelative(0, -CHIGHDOTS); strIdx++; } } else { MoveAbsolute(-3 * CWIDEDOTS, -CHIGHDOTS); PrintText(AxisTitles[Y], pg, vgOutput); } AxisTitles[Y] = null; } RecallPosition(); } private void DoBoxes(VG.Page pg, IVGOutput vgOutput) { int dx, dy; XyBox current; string str; SavePosition(); int BoxIdx = 0; SetPenDiameter(5); while (BoxIdx < AllBoxes.Count) { current = AllBoxes[BoxIdx]; MoveTo(current.BoxMinimum); dx = current.BoxMaximum.xyValue[X] - current.BoxMinimum.xyValue[X]; dy = current.BoxMaximum.xyValue[Y] - current.BoxMinimum.xyValue[Y]; if (current.Shadow != 2) BoxRelative(dx, dy, CurPenWidth, pg, vgOutput); if (current.Shadow == 1) { int savePenWidth = CurPenWidth; SavePosition(); SetPenDiameter(10); MoveRelative((int)(10 * ConvertToTwips), -(dy + (int)(5 * ConvertToTwips))); DrawRelative(dx, 0, pg, vgOutput); MoveRelative(-(int)(3 * ConvertToTwips), -(int)(5 * ConvertToTwips)); DrawRelative(0, dy, pg, vgOutput); CurPenWidth = savePenWidth; RecallPosition(); } MoveRelative((CWIDEDOTS * (3 / 2)), -(CHIGHDOTS * (5 / 4))); str = current.BoxText; int stridx = 0; while (stridx < str.Length) { string tstr = str; int idx; if ((idx = str.IndexOf("\n", stridx)) >= 0) { tstr = str.Substring(stridx, idx - stridx); stridx = idx + 1; } else stridx = str.Length + 1; PrintText(tstr, pg, vgOutput); MoveRelative(0, -CHIGHDOTS); } BoxIdx++; } RecallPosition(); } private void DrawLines(VG.Page pg, IVGOutput vgOutput) { int PlotsIdx = 0; DataPoint curpoint; PlotLine current; SavePosition(); SetPenDiameter(8); /* begin plotting the graph lines, which may be straight or curved */ while (PlotsIdx < AllPlots.Count) { current = AllPlots[PlotsIdx]; int pntListIdx = 0; LineDiv = current.PlotDivisions; if (current.PlotType == STRAIGHT) { /* straight plot */ curpoint = current.PlotDataPoints[pntListIdx]; MoveTo(curpoint.APoint); while (++pntListIdx < current.PlotDataPoints.Count) { curpoint = current.PlotDataPoints[pntListIdx]; DrawLineTo(curpoint.APoint, pg, vgOutput); } } else { DrawCurve(current, pg, vgOutput); /* curved plot */ } PlotsIdx++; } /* repeat for each plot (while) */ RecallPosition(); } private point FindCenterOfArc(point StartPoint, double Slope1, point EndPoint, double Slope2) { point center = new point(); double s1, s2; int x1, y1, x2, y2; center.xyValue = new int[Dimensions]; s1 = tan_deg(FixAngle(atan_deg(Slope1))); s2 = tan_deg(FixAngle(atan_deg(Slope2))); x1 = StartPoint.xyValue[X]; y1 = StartPoint.xyValue[Y]; x2 = EndPoint.xyValue[X]; y2 = EndPoint.xyValue[Y]; center.xyValue[X] = (int)(((s2 * s1) * (y2 - y1) + (s1 * x2) - (s2 * x1)) / (s1 - s2)); if (s1 == 0.0) center.xyValue[Y] = (int)(y2 - ((center.xyValue[X] - x2) / s2)); else center.xyValue[Y] = (int)(y1 - ((center.xyValue[X] - x1) / s1)); return (center); } private point FindModifiedCenter(double rprime, point PtOnArc, double ang) { point newcenter = new point(); newcenter.xyValue = new int[Dimensions]; newcenter.xyValue[X] = (int)(PtOnArc.xyValue[X] - rprime * cos_deg(ang)); newcenter.xyValue[Y] = (int)(PtOnArc.xyValue[Y] - rprime * sin_deg(ang)); return (newcenter); } private int AddMidPoint(DataPoints ptLstAry, int pt1Idx, int pt2Idx) { DataPoint midpt; DataPoint pt1, pt2; point pt; double so; int x1, y1, x2, y2; pt1 = ptLstAry[pt1Idx]; pt2 = ptLstAry[pt2Idx]; x1 = pt1.APoint.xyValue[X]; y1 = pt1.APoint.xyValue[Y]; x2 = pt2.APoint.xyValue[X]; y2 = pt2.APoint.xyValue[Y]; midpt = new DataPoint(); pt = new point(); pt.xyValue = new int[Dimensions]; so = FindSlope(pt1.APoint, pt2.APoint); midpt.slope = (4.0 * so - pt1.slope - pt2.slope) / 2.0; pt.xyValue[X] = x1 + (x2 - x1) / 2; pt.xyValue[Y] = y1 + (y2 - y1) / 2; midpt.APoint = pt; ptLstAry.Insert(pt1Idx + 1, midpt); return (pt1Idx + 1); } private double FindTheta(point Endpoint, point Centerpoint) { double dy, dx, result; dx = Endpoint.xyValue[X] - Centerpoint.xyValue[X]; dy = Endpoint.xyValue[Y] - Centerpoint.xyValue[Y]; result = 90.0 - atan_deg((dy / dx)); if (dx < 0) result += 180.0; return (result); } private double FindRadius(point Endpoint, point Centerpoint) { double dy, dx, r; dx = Centerpoint.xyValue[X] - Endpoint.xyValue[X]; dy = Centerpoint.xyValue[Y] - Endpoint.xyValue[Y]; r = Math.Sqrt(((dx * dx) + (dy * dy))); return (r); } private void DrawCurve(PlotLine linestart, VG.Page pg, IVGOutput vgOutput) { CheckDataPoints(linestart); int pltptListIdx = -1; while (++pltptListIdx < linestart.PlotDataPoints.Count - 1) { DoSubArcs(linestart.PlotDataPoints, pltptListIdx, pg, vgOutput); } } private void CheckDataPoints(PlotLine linestart) { for(int i = 0;i x1) { XYPlotIssue = "X Values should be Increasing"; throw new Exception("Curve has Invalid Values"); } } } private double GetAngle(double s1) { double t1; t1 = atan_deg(s1); return (t1); } private double GetAngleBetweenPoints(point pt1, point pt2) { double retval; retval = GetAngle(FindSlope(pt1, pt2)); if (pt2.xyValue[X] < pt1.xyValue[X]) { if (retval < 0) retval += 180; else retval -= 180; } return (retval); } private double SpecialGetAngleBetweenPoints(point pt1, point pt2, double s1) { double retval; if (s1 == 0.0) { if (pt1.xyValue[Y] < pt2.xyValue[Y]) s1 = Convert.ToDouble("1.E99"); else s1 = Convert.ToDouble("-1.E99"); } else s1 = -1 / s1; retval = GetAngle(s1); if (pt2.xyValue[X] < pt1.xyValue[X]) { if (retval < 0) retval += 180; else retval -= 180; } return (retval); } private double GetArcAngle(double s1, double s2) { double result, t1, t2; t1 = GetAngle(s1); t2 = GetAngle(s2); result = t1 - t2; return (result); } private void DoSubArcs(DataPoints dataPoints, int aryIdx, VG.Page pg, IVGOutput vgOutput) { bool debug = false; //jsj int x, y, x1, x2, y1, y2; DataPoint pt1 = dataPoints[aryIdx]; DataPoint pt2 = dataPoints[aryIdx + 1]; DebugOutput("pt1={0},{1},{2}", pt1.APoint.xyValue[0], pt1.APoint.xyValue[1], pt1.slope); DebugOutput("pt2={0},{1},{2}", pt2.APoint.xyValue[0], pt2.APoint.xyValue[1], pt2.slope); double theta, delta1, delta2, r1, r2, t1, t2, theta1, theta2, thetaa, t3, t4; double c1, c2, s1, s2; double t3a, t4a; point cp1, cp2; t3 = FixAngle(t3a=GetAngle(pt1.slope)); t4 = FixAngle(t4a=GetAngle(pt2.slope)); thetaa = GetAngleBetweenPoints(pt1.APoint, pt2.APoint); if ((t3 - thetaa) * (t4 - thetaa) >= 0.0) { double tprime; tprime = FixAngle(thetaa); if (Math.Abs(tprime - t3) <= ANGLELIMIT) { MoveTo(pt1.APoint); DrawTo(pt2.APoint, pg, vgOutput); return; } else { pt2 = dataPoints[AddMidPoint(dataPoints, aryIdx, aryIdx + 1)]; t4 = FixAngle(GetAngle(pt2.slope)); thetaa = GetAngleBetweenPoints(pt1.APoint, pt2.APoint); } } if (thetaa < t3) t1 = t3 + 90; else t1 = t3 - 90; if (thetaa > t4) t2 = t4 + 90; else t2 = t4 - 90; theta = t2 - t1; theta1 = FixAngle(thetaa - t3); theta2 = theta - theta1; if (Math.Abs(theta1) < Math.Abs(theta2)) { if (Math.Abs(theta1) < ANGLELIMIT) { theta1 = 0; theta2 = theta; } } else if (Math.Abs(theta2) < Math.Abs(theta1)) { if (Math.Abs(theta2) < ANGLELIMIT) { theta2 = 0; theta1 = theta; } } x1 = pt1.APoint.xyValue[X]; y1 = pt1.APoint.xyValue[Y]; x2 = pt2.APoint.xyValue[X]; y2 = pt2.APoint.xyValue[Y]; s1 = sin_deg(t1 + 180); s2 = sin_deg(t2 + 180); c1 = cos_deg(t1 + 180); c2 = cos_deg(t2 + 180); if (s1 == 0.0) { r2 = (x1 - x2) / s2; r1 = (y2 + r2 * c2 - y1) / c1; } else if (s2 == 0.0) { r1 = (x2 - x1) / s1; r2 = (y1 + r1 * c1 - y2) / c2; } else if (c1 == 0.0) { r2 = (y1 - y2) / c2; r1 = (x2 + r2 * s2 - x1) / s1; } else if (c2 == 0.0) { r1 = (y2 - y1) / c1; r2 = (x1 + r1 * s1 - x2) / s2; } else { r2 = (((x2 - x1) / c1) - ((y2 - y1) / s1)) / (s2 / s1 - c2 / c1); r1 = (y2 - y1 + r2 * s2) / s1; } MoveTo(pt1.APoint); if (debug) //jsj { DrawTo(pt2.APoint, pg, vgOutput); return; } if (Math.Abs(theta1) > ANGLELIMIT && Math.Abs(theta2) > ANGLELIMIT) { delta1 = (r2 - r1) / ( (1.0 - cos_deg(theta1)) + (1.0 - cos_deg(theta2)) * sin_deg(theta1) / sin_deg(theta2)); r1 = Math.Floor(0.5 + r1 + delta1); cp1 = FindModifiedCenter(r1, pt1.APoint, t1); x = (int)(cp1.xyValue[X] + r1 * cos_deg(t1 + theta1)); y = (int)(cp1.xyValue[Y] + r1 * sin_deg(t1 + theta1)); delta2 = delta1 * sin_deg(theta1) / sin_deg(theta2); r2 = Math.Floor(0.5 + r2 - delta2); cp2 = FindModifiedCenter(r2, pt2.APoint, t2); //#if DEBUG //DebugOutput("DrawArc1"); VG_Arc.iColor = 1; //#endif DrawArc(r1, t1, t1 + theta1, cp1, x, y, pg, vgOutput); DebugShowLocation("DrawArc1"); MoveTo(pt2.APoint); DebugShowLocation("MoveTo1"); if (r2 > 15000) { DebugOutput("DrawAbs1 {0},{1}", x, y); DrawAbsolute(x, y, pg, vgOutput); DebugShowLocation("DrawAbs1"); } else { //#if DEBUG //DebugOutput("DrawArc2"); VG_Arc.iColor = 2; //#endif DrawArc(r2, t2, t2 - theta2, cp2, x, y, pg, vgOutput); DebugShowLocation("DrawArc2"); } } else if (Math.Abs(theta1) > ANGLELIMIT) { delta1 = (r2 - r1) / (1.0 - cos_deg(theta1)); r1 = Math.Floor(0.5 + r1 + delta1); if (r1 < 0) r1 = -r1; cp1 = FindModifiedCenter(r1, pt1.APoint, t1); x = (int)(cp1.xyValue[X] + r1 * cos_deg(t1 + theta1)); y = (int)(cp1.xyValue[Y] + r1 * sin_deg(t1 + theta1)); if (r1 > 15000) { DebugOutput("DrawAbs2"); DrawAbsolute(x, y, pg, vgOutput); DebugShowLocation("DrawAbs2"); } else { //Console.WriteLine("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9}", t3, t3a, t4, t4a, thetaa, t1, t2, r1, r2, aryIdx); //#if DEBUG //DebugOutput("DrawArc3"); VG_Arc.iColor = 3; //VG_Arc.iColor = 4; //#endif DrawArc(r1, t1, t1 + theta1, cp1, x, y, pg, vgOutput); //Console.WriteLine("'DrawArc3','{0}',{1},{2}", Key, r1, theta1); DebugShowLocation("DrawArc3"); } MoveAbsolute(x, y); DebugShowLocation("MoveAbs2"); DebugOutput("DrawTo1"); DrawTo(pt2.APoint, pg, vgOutput); DebugShowLocation("DrawTo1"); //DebugOutput("DrawArc4"); VG_Arc.iColor = 4; //DrawArc(r1, t1, t1 + theta1, cp1, x, y, pg, vgOutput); //DebugShowLocation("DrawArc4"); } else if (Math.Abs(theta2) > ANGLELIMIT) { delta2 = (r2 - r1) / (1.0 - cos_deg(theta2)); r2 = Math.Floor(0.5 + r2 - delta2); if (r2 < 0) r2 = -r2; cp2 = FindModifiedCenter(r2, pt2.APoint, t2); x = (int)(cp2.xyValue[X] + r2 * cos_deg(t2 - theta2)); y = (int)(cp2.xyValue[Y] + r2 * sin_deg(t2 - theta2)); DebugOutput("DrawAbs3"); DrawAbsolute(x, y, pg, vgOutput); DebugShowLocation("DrawAbs3"); MoveTo(pt2.APoint); DebugShowLocation("MoveTo1"); if (r2 > 15000) { DebugOutput("DrawAbs4"); DrawAbsolute(x, y, pg, vgOutput); DebugShowLocation("DrawAbs4"); } else { //#if DEBUG //DebugOutput("DrawArc5"); VG_Arc.iColor = 5; //VG_Arc.iColor = 6; //#endif if (r2 != 0) DrawArc(r2, t2, t2 - theta2, cp2, x, y, pg, vgOutput); DebugShowLocation("DrawArc5"); } //DebugOutput(""); VG_Arc.iColor = 6; //DrawArc(r2, t2, t2 - theta2, cp2, x, y, pg, vgOutput); //DebugShowLocation("DrawArc6"); } else { DebugOutput("DrawTo2"); DrawTo(pt2.APoint, pg, vgOutput); DebugShowLocation("DrawTo2"); pt2.slope = FindSlope(pt1.APoint, pt2.APoint); } return; } private void SetPenDiameter(int pd) { if ((pd * ConvertToTwips) != CurPenWidth) { CurPenWidth = (int)(pd * ConvertToTwips); } } private void PrintStackError(string relation, int limit) { MessageBox.Show(String.Format("Position Stack Pointer {0} {1}", relation, limit.ToString()), "Print Stack Error"); } private void SavePosition() { if (stack >= MAX_XY_STACK) PrintStackError(">=", MAX_XY_STACK); SavedX[stack] = Position[X]; SavedY[stack++] = Position[Y]; } private void RecallPosition() { if (stack <= 0) PrintStackError(" <", 0); Position[X] = SavedX[--stack]; Position[Y] = SavedY[stack]; } private void MoveTo(point pnt) { MoveAbsolute(pnt.xyValue[X], pnt.xyValue[Y]); } private void DrawTo(point pnt, VG.Page pg, IVGOutput vgOutput) { DrawAbsolute(pnt.xyValue[X], pnt.xyValue[Y], pg, vgOutput); } private void MoveAbsolute(int ptx, int pty) { int x, y; x = ptx - Position[X]; y = Position[Y] - pty; MoveRelative(x, y); } private void DrawAbsolute(int ptx, int pty, VG.Page pg, IVGOutput vgOutput) { int x, y; x = ptx - Position[X]; y = Position[Y] - pty; DrawRelative(x, y, pg, vgOutput); } private void DrawGridAbsolute(int ptx, int pty, VG.Page pg, IVGOutput vgOutput) { int x, y; x = ptx - Position[X]; y = Position[Y] - pty; DrawGridRelative(x, y, pg, vgOutput); } private void relval(string ptr, int i) { ptr = string.Format("+{0}", i.ToString()); } private void MoveRelative(int x, int y) { Position[X] += x; Position[Y] -= y; } private void DrawRelative(int x, int y, VG.Page pg, IVGOutput vgOutput) { if (Visible == 0) MoveRelative(x, y); else { int toX, toY; toX = Position[X] + x; toY = Position[Y] - y; VG_Line RelLine = new VG_Line(Position[X], Position[Y], toX, toY, CurPenWidth, pg); Position[X] += x; Position[Y] -= y; RelLine.Draw(vgOutput); } } private void DrawGridRelative(int x, int y, VG.Page pg, IVGOutput vgOutput) { if (Visible == 0) MoveRelative(x, y); else { DrawRelative(x, y, pg, vgOutput); } } private void DrawArc(double radius, double Sangle, double Eangle, point cp, int x, int y, VG.Page pg, IVGOutput vgOutput) { DebugOutput("r={0} sAngle={1} eAngle={2} cp={3},{4} x={5} y={6}", radius, Sangle, Eangle, cp.xyValue[0], cp.xyValue[1], x, y); int dx, dy; long radchk; radchk = (long)radius; if (radchk > 72000L) { DrawAbsolute(x, y, pg, vgOutput); return; } dx = x - cp.xyValue[X]; //jj dy = Math.Abs(cp.xyValue[Y] - Position[Y]); //jj float x1 = cp.xyValue[X] - (float)radius; float y1 = cp.xyValue[Y] - (float)radius; float w1 = (float)radius * 2; VG_Arc arc = new VG_Arc(x1, y1, w1, w1, (float)Sangle, (float)(Eangle - Sangle), CurPenWidth, pg); DebugOutput("arc {0},{1},{2},{3},{4},{5}", x1, y1, w1, w1, (float)Sangle, (float)(Eangle - Sangle)); arc.Draw(vgOutput); } private void DrawGridLine(int flag, int val, VG.Page pg, IVGOutput vgOutput) { XyBox curbox; int v1, v2; int BoxesIdx = 0; FindBoxesinArea(val, (flag == 0) ? 1 : 0); v1 = Position[flag]; if (ActiveBoxes.Count > 0) { curbox = ActiveBoxes[BoxesIdx]; while (BoxesIdx < ActiveBoxes.Count) { int my_x, my_y; v2 = curbox.BoxMinimum.xyValue[flag]; my_x = (flag == X) ? ((v2 < printerunits[flag]) ? v2 : printerunits[flag]) : val; my_y = (flag == Y) ? ((v2 < printerunits[flag]) ? v2 : printerunits[flag]) : val; DrawGridAbsolute(my_x, my_y, pg, vgOutput); v1 = curbox.BoxMaximum.xyValue[flag]; while ((BoxesIdx < ActiveBoxes.Count) && (curbox.BoxMinimum.xyValue[flag] < v1)) { v1 = (curbox.BoxMaximum.xyValue[flag]); BoxesIdx++; if (BoxesIdx < ActiveBoxes.Count) curbox = ActiveBoxes[BoxesIdx]; } MoveAbsolute((flag == X ? v1 : val), (flag == Y ? v1 : val)); } } v2 = printerunits[flag]; if (v1 < v2) DrawGridAbsolute((flag == X ? v2 : val), (flag == Y ? v2 : val), pg, vgOutput); ActiveBoxes.Clear(); } private void LogScale(int flag) { double newminimum, newmaximum, maxlimit = maximum[flag] * .9; newminimum = 1.0; while (newminimum < minimum[flag]) newminimum *= 10.0; while (newminimum > minimum[flag]) newminimum /= 10.0; newmaximum = 10.0 * newminimum; cycles[flag] = 1; while (newmaximum < maxlimit) { newmaximum *= 10.0; cycles[flag]++; } onecycle[flag] = printerunits[flag] / cycles[flag]; minimum[flag] = newminimum; maximum[flag] = newmaximum; } private void LinearScale(int flag) { double mantissa, nx; double newminimum, newmaximum; int power = 0; if (spcminor[flag] == 0) minor[flag] = 10; else minor[flag] = spcminor[flag]; if (delta[flag] == 0) { delta[flag] = maximum[flag] - minimum[flag]; mantissa = Math.Log10(delta[flag]); while (mantissa < 1.2) { mantissa++; power--; } while (mantissa > 1.2) { mantissa--; power++; } if (mantissa < 0) mantissa = 0; nx = Math.Pow(10.0, mantissa); if (nx > 5.0) { delta[flag] = 1.0; } else if (nx > 3.001) { // allow for roundoff delta[flag] = 0.5; } else if (nx > 2.001) { // allow for roundoff delta[flag] = 0.25; } else { delta[flag] = 0.2; if (spcminor[flag] == 0) minor[flag] = 8; } while (power > 0) { power--; delta[flag] *= 10.0; } while (power < 0) { power++; delta[flag] /= 10.0; } } if (GridOnFlag == 0 || GridOnFlag == 1) minor[flag] = 1; else if (GridOnFlag == 2) minor[flag] /= 2; newminimum = ((int)(0.01 + minimum[flag] / delta[flag])) * delta[flag]; if (newminimum > minimum[flag] + (delta[flag] * 0.001)) newminimum -= delta[flag]; newmaximum = ((int)(maximum[flag] / delta[flag])) * delta[flag]; if (newmaximum < maximum[flag] - (delta[flag] * 0.001)) newmaximum += delta[flag]; // B2017-008 Support a reverse Axis which goes from a larger value to a smaller value. if (newmaximum < newminimum) delta[flag] = -delta[flag]; minimum[flag] = newminimum; maximum[flag] = newmaximum; } private void err_exit(string msg, string msg2) { MessageBox.Show(msg + "\n" + msg2 + "\n\n This p=Process Will Terminate", "\n## ERROR ## - "); Environment.Exit(255); } private void FindBoxesinArea(int ptval, int flag) { XyBox cptr; int BoxesIdx = 0; while (BoxesIdx < AllBoxes.Count) { cptr = AllBoxes[BoxesIdx]; if (cptr.BoxMinimum.xyValue[flag] <= ptval && cptr.BoxMaximum.xyValue[flag] >= ptval) if(cptr.BoxMinimum.xyValue[1-flag] > 0 && cptr.BoxMaximum.xyValue[1 - flag] < printerunits[1-flag])// Don't include box if it is outside of the range of the grid. AddBoxToActiveList(cptr); BoxesIdx++; } } private void AddBoxToActiveList(XyBox box) { int i = 0; while (i < ActiveBoxes.Count) { if (box.BoxMinimum.xyValue[DrawDirection] < ActiveBoxes[i].BoxMinimum.xyValue[DrawDirection]) break; // Located the location to insert the box i++; } ActiveBoxes.Insert(i, box); } private void GenGrid(int flag, int ss, int ee, int dd, int w, int lw, int goffset, VG.Page pg, IVGOutput vgOutput) { int val, wn, valn; double p2; int n, dn, MinorGrid = 0; if ((GridOnFlag * lw) <= 1) return; if (ee / ss == 10) MinorGrid = 2; n = ss; p2 = n; w = (int)(w / Math.Log10(ee / p2)); //jj val = (int)(Math.Log10(p2 / ss) * w + goffset); MoveAbsolute((flag == X ? val : 0), (flag == Y ? val : 0)); DrawGridLine((flag == 0) ? 1 : 0, val, pg, vgOutput); if ((GridOnFlag * lw) == 2) return; SetPenDiameter(lw); while (n < ee) { n += dd; p2 = n; valn = (int)(Math.Log10(p2 / ss) * w + goffset); wn = valn - val; if (wn > DPI / 20 && lw > 1) { if (wn > DPI * 2 / 5) dn = dd / 10; else if (wn > DPI / 5) dn = dd / 5; else dn = dd / 2; GenGrid(flag, n - dd, n, dn, wn, lw - 1, val, pg, vgOutput); wn = 0; } val = valn; if (flag == Y) val = printerunits[Y] - val; //jj MoveAbsolute((flag == X ? val : 0), (flag == Y ? val : 0)); if ((MinorGrid != 0) && (MinorGrid < 10)) { WriteValue(flag, MinorGrid++, true, pg, vgOutput); //these numbers are in dots } DrawGridLine((flag == 0) ? 1 : 0, val, pg, vgOutput); } } private void PrintText(string txt, VG.Page pg, IVGOutput vgOutput) { StringBuilder tstr = new StringBuilder(txt); int ptr; SavePosition(); /* 'cause TEXT...,E screws up position! */ ptr = 0; while (ptr < tstr.Length) { if ("`øòó".IndexOf(tstr[ptr]) >= 0) { string SpecialChar = ""; switch ((byte)tstr[ptr]) { case 0x60: /* backquote */ case 0xF8: SpecialChar = "\u00B0"; /* degree symbol */ break; case 0xF2: SpecialChar = "\u2265"; /* greaterthanequal */ break; case 0xF3: SpecialChar = "\u2264"; /* lessthanequal */ break; } tstr.Remove(ptr, 1); tstr.Insert(ptr, SpecialChar); ptr++; } else { ptr++; } } GraphText(tstr.ToString(), pg, vgOutput); RecallPosition(); } private void FreeBoxList() { AllBoxes.Clear(); } private void FreeLineList() { AllPlots.Clear(); } private void Init_Graphic_Vars() { int i; SavedX = new int[MAX_XY_STACK]; SavedY = new int[MAX_XY_STACK]; LinesUsed = 0; /* Number lines used by graph, in dots */ Visible = 1; ShadowFlag = 0; CurPenWidth = 0; DrawDirection = -1; AxisTitles[X] = null; AxisTitles[Y] = null; AxisLabel[0] = 1; AxisLabel[1] = 1; EndFlag = 0; for (i = 0; i < Dimensions; i++) { Scale[0, i] = 0; Scale[1, i] = 0; Offset[0, i] = 0; Offset[1, i] = 0; delta[i] = 0; cycles[i] = 0; onecycle[i] = 0; minor[i] = 0; } } private void DrawLineTo(point pnt, VG.Page pg, IVGOutput vgOutput) { int x1, y1, x2, y2; int nd, x, y, i; long ddx, ddy, dx, dy; x1 = Position[X]; y1 = Position[Y]; x2 = pnt.xyValue[X]; y2 = pnt.xyValue[Y]; if (LineDiv != 0) { nd = LineDiv * 4; dx = x2 - x1; dy = y2 - y1; for (i = 1; i <= nd; i++) { ddx = dx * i; ddy = dy * i; x = (int)(x1 + ddx / nd); y = (int)(y1 + ddy / nd); if ((i & 2) != 0) MoveAbsolute(x, y); else DrawAbsolute(x, y, pg, vgOutput); } } else DrawTo(pnt, pg, vgOutput); } private void BoxRelative(int dx, int dy, int LineWidth, VG.Page pg, IVGOutput vgOutput) { VG_Rect vgrec = new VG_Rect((int)Position[X], (int)Position[Y], dx, dy, LineWidth, pg); vgrec.Draw(vgOutput); } private void GraphText(string txt, VG.Page pg, IVGOutput vgOutput) { // Look for a Superscript or Subsript. // - break up the string (if needed) and change the font pitch // for the text that is to be super/subscripted VG_Text drawText; string tstr = ""; int Xpos, Ypos; int sidx = 0; // beginning of string int idx = 0; // current position in string Xpos = Position[X]; Ypos = Position[Y]; while (idx < txt.Length) { int tidx; if ((tidx = txt.IndexOf(SuperScript[0], idx)) > -1) { // print text up to the superscript tstr = txt.Substring(sidx, tidx - sidx); drawText = new VG_Text(Xpos, Ypos, (int)FontPitch, tstr, MyFontFamily, "", "", "", pg); drawText.Draw(vgOutput); Xpos += (CWIDEDOTS * tstr.Length); tidx += SuperScript[0].Length; idx = tidx; sidx = idx; tidx = txt.IndexOf(SuperScript[1], idx); if (tidx > 0) { // switch font pitch, move up some, and print the superscript text tstr = txt.Substring(sidx, tidx - sidx); Ypos -= (CHIGHDOTS / 2); // move up half a char heigth drawText = new VG_Text(Xpos, Ypos, (int)(FontPitch / 2), tstr, MyFontFamily, "", "", "", pg); drawText.Draw(vgOutput); Ypos += (CHIGHDOTS / 2); // move back down Xpos += ((CWIDEDOTS / 2) * tstr.Length); // positon half the width of the string tidx += SuperScript[1].Length; idx = tidx; sidx = idx; continue; // go back to beginning of while loop } } else if ((tidx = txt.IndexOf(SubScript[0], idx)) > -1) { // print text up to the superscript tstr = txt.Substring(sidx, tidx - sidx); drawText = new VG_Text(Xpos, Ypos, (int)FontPitch, tstr, MyFontFamily, "", "", "", pg); drawText.Draw(vgOutput); Xpos += (CWIDEDOTS * tstr.Length); tidx += SubScript[0].Length; idx = tidx; sidx = idx; tidx = txt.IndexOf(SubScript[1], idx); if (tidx > 0) { // switch font pitch, move up some, and print the superscript text tstr = txt.Substring(sidx, tidx - sidx); drawText = new VG_Text(Xpos, Ypos, (int)(FontPitch / 2), tstr, MyFontFamily, "", "", "", pg); drawText.Draw(vgOutput); Xpos += ((CWIDEDOTS / 2) * tstr.Length); // positon half the width of the string tidx += SubScript[1].Length; idx = tidx; sidx = idx; continue; // go back to beginning of while loop } } else { idx++; } } // end while if (sidx < txt.Length) { tstr = txt.Substring(sidx); drawText = new VG_Text(Xpos, Ypos, (int)FontPitch, tstr, MyFontFamily, "", "", "", pg); drawText.Draw(vgOutput); } } /// /// Generates a vgOutput files containing an X/Y PLot generated from the passed in /// commands. /// /// Plot Commands public XYPlot(string PlotCommands) { // MSWord enters left and right double-quotes when you press the double-quote key //B2017 - Replace left and right double-quotes with normal double-quotes PlotCommands = PlotCommands.Replace('\u201C', '"').Replace('\u201D', '"'); LoadBuffFromString(PlotCommands); Setup(); //#if DEBUG //VG.VG_Arc.iColor = 0; //#endif } private int _OffsetX = 0; public int OffsetX { get { return _OffsetX; } set { _OffsetX = value; } } private int _OffsetY = 0; public int OffsetY { get { return _OffsetY; } set { _OffsetY = value; } } public void Setup() { char Command, PrevCommand = ' '; Init_Graphic_Vars(); FixBuffIfNeeded(); GetScaleInfo(); while ((Command = char.ToUpper(getchr())) != '\0') { LineDiv = 0; LineFlag = CURVE; ShadowFlag = 0; switch (Command) { case 'O': OffsetX = getint(); OffsetY = getint(); break; case 'T': ShadowFlag += 2; // 2 for no box GetBoxParameters(); break; case 'W': ShadowFlag++; // 1 for shadow box GetBoxParameters(); break; case 'B': GetBoxParameters(); // 0 for box break; case 'D': LineDiv = getint(); LineFlag = STRAIGHT; GetLineParameters(); break; case 'L': LineFlag = STRAIGHT; GetLineParameters(); break; case 'C': GetLineParameters(); break; case 'X': GetAxisTitle(X); break; case 'Y': GetAxisTitle(Y); break; case 'Z': YLandScape = 1; YTitleOrigin = GetPair(USER); GetAxisTitle(Y); break; case 'A': AxisLabel[0] = getint(); AxisLabel[1] = getint(); break; default: if (PrevCommand.Equals(null)) MessageBox.Show("Check the first line of the X/Y Plot definition.", "Unrecognized Graph Command"); else MessageBox.Show(string.Format("Problem with the X/Y Plot Command after {0}", PrevCommand.ToString()), "Unrecognized Graph Command"); break; } PrevCommand = Command; } } public void Process(IVGOutput vgOutput) { VG.Page pg = new Page(true, _LeftMargin, _TopMargin, _RightMargin, _BottomMargin); string step = "Process"; try // C2018-035 Added error Handling to Process to provide more useful information when a plot fails { step = "GenerateGrid";GenerateGrid(pg, vgOutput); step = "DoAxisTitles";DoAxisTitles(pg, vgOutput); step = "DrawLines";DrawLines(pg, vgOutput); step = "DoBoxes";DoBoxes(pg, vgOutput); step = "FreeBoxList";FreeBoxList(); step = "FreeLineList";FreeLineList(); step = "CloseGraph";CloseGraph(); } catch (Exception ex) { _MyLog.WarnFormat("X/Y Plot Error - {0} - {1} - {2}", step, XYPlotIssue ?? "Unknown Issue"); throw new Exception(String.Format("X/Y Plot Error - {0} - {1}",step,XYPlotIssue ?? "Unknown Issue")); } } private void ShowPoints(DataPoints dataPoints) { //#if DEBUG //foreach (DataPoint pl in dataPoints) //{ // DebugOutput("x={0},y={1},slope={2}", pl.APoint.xyValue[0], pl.APoint.xyValue[1], pl.slope); //} //#endif } public static string Key = ""; private void DebugOutput(string format, params object[] args) { //#if DEBUG //if (args.Length == 0) // Console.WriteLine("'{0}','{1}'",Key,format); //Console.WriteLine(format, args); //#endif } private void DebugShowLocation(string command) { //Console.WriteLine("'{0}',{1},{2}", command, Position[X], Position[Y]); } } }