예제 #1
0
파일: Scope.cs 프로젝트: mctr909/CircuitSim
 void _allocImage()
 {
     if (mContext == null)
     {
         mContext = CustomGraphics.FromImage(BoundingBox.Width, BoundingBox.Height);
     }
 }
예제 #2
0
파일: Scope.cs 프로젝트: mctr909/CircuitSim
        void _drawSettingsWheel(CustomGraphics g)
        {
            const int outR   = 6 * 18 / 16;
            const int inR    = 4 * 18 / 16;
            const int inR45  = 3 * 18 / 16;
            const int outR45 = 4 * 18 / 16;

            if (mShowSettingsWheel)
            {
                if (CursorInSettingsWheel)
                {
                    g.LineColor = Color.Cyan;
                }
                else
                {
                    g.LineColor = Color.DarkGray;
                }
                g.SetTransform(new Matrix(1, 0, 0, 1, BoundingBox.X + 12, BoundingBox.Y + BoundingBox.Height - 16));
                g.DrawCircle(new Point(), inR);
                g.DrawLine(-outR, 0, -inR, 0);
                g.DrawLine(outR, 0, inR, 0);
                g.DrawLine(0, -outR, 0, -inR);
                g.DrawLine(0, outR, 0, inR);
                g.DrawLine(-outR45, -outR45, -inR45, -inR45);
                g.DrawLine(outR45, -outR45, inR45, -inR45);
                g.DrawLine(-outR45, outR45, -inR45, inR45);
                g.DrawLine(outR45, outR45, inR45, inR45);
                g.ClearTransform();
            }
        }
예제 #3
0
파일: Scope.cs 프로젝트: mctr909/CircuitSim
        void _drawFFTVerticalGridLines(CustomGraphics g)
        {
            /* Draw x-grid lines and label the frequencies in the FFT that they point to. */
            int    prevEnd      = 0;
            int    divs         = 20;
            double maxFrequency = 1 / (ControlPanel.TimeStep * Speed * divs * 2);

            g.LineColor = Color.FromArgb(0x88, 0x00, 0x00);
            for (int i = 0; i < divs; i++)
            {
                int x = BoundingBox.Width * i / divs;
                if (x < prevEnd)
                {
                    continue;
                }
                string s      = ((int)Math.Round(i * maxFrequency)) + "Hz";
                int    sWidth = (int)Math.Ceiling(g.GetTextSize(s).Width);
                prevEnd = x + sWidth + 4;
                if (i > 0)
                {
                    g.DrawLine(x, 0, x, BoundingBox.Height);
                }
                g.DrawLeftText(s, x + 2, BoundingBox.Height - 12);
            }
        }
예제 #4
0
파일: Scope.cs 프로젝트: mctr909/CircuitSim
 void _drawInfoText(CustomGraphics g, string text)
 {
     if (BoundingBox.Y + BoundingBox.Height <= mTextY + 5)
     {
         return;
     }
     g.DrawLeftText(text, 0, mTextY);
     mTextY += 15;
 }
예제 #5
0
파일: Scope.cs 프로젝트: mctr909/CircuitSim
        void _drawInfoTexts(CustomGraphics g)
        {
            mTextY = 10;
            var plot = mVisiblePlots[0];

            if (ShowScale)
            {
                string vScaleText = "";
                if (mGridStepY != 0 && (!ShowV))
                {
                    vScaleText = " V=" + plot.GetUnitText(mGridStepY) + "/div";
                }
                _drawInfoText(g, "H=" + Utils.UnitText(mGridStepX, "s") + "/div" + vScaleText);
            }
            if (ShowMax)
            {
                _drawInfoText(g, plot.GetUnitText(mMaxValue));
            }
            if (ShowMin)
            {
                int ym = BoundingBox.Height - 5;
                g.DrawLeftText(plot.GetUnitText(mMinValue), 0, ym);
            }
            if (ShowRMS)
            {
                _drawRMS(g);
            }
            string t = Text;

            if (t == null)
            {
                t = mScopeText;
            }
            if (t != null)
            {
                _drawInfoText(g, t);
            }
            if (ShowFreq)
            {
                _drawFrequency(g);
            }
        }
        public void CreateDialog()
        {
            InitializeComponent();

            mPnlV          = new Panel();
            mPnlV.AutoSize = true;

            mCanvas = new PictureBox()
            {
                Width = 320, Height = 320
            };
            mBmp = new Bitmap(mCanvas.Width, mCanvas.Height);
            mG   = CustomGraphics.FromImage(mBmp);
            mPnlV.Controls.Add(mCanvas);

            mChip      = new CustomCompositeChipElm(new Point(50, 50));
            mChip.P2.X = 200;
            mChip.P2.Y = 50;
            createPinsFromModel();

            var lbl = new Label()
            {
                Top = mCanvas.Bottom, AutoSize = true, Text = "Model Name"
            };

            mPnlV.Controls.Add(lbl);
            mModelNameTextBox = new TextBox()
            {
                Top = lbl.Bottom
            };
            mModelNameTextBox.Enabled = string.IsNullOrEmpty(mModel.Name);
            mModelNameTextBox.Text    = mModel.Name;
            mPnlV.Controls.Add(mModelNameTextBox);

            var pnlSize = new Panel();
            {
                pnlSize.Top      = mModelNameTextBox.Bottom;
                pnlSize.AutoSize = true;
                int ofsY = 0;
                var lblW = new Label()
                {
                    Top = ofsY, AutoSize = true, Text = "Width"
                };
                pnlSize.Controls.Add(lblW);
                ofsY += lblW.Height;
                /* Width+ */
                var bwp = new Button()
                {
                    Top = ofsY, Width = 40, Text = "+"
                };
                bwp.Click += new EventHandler((s, e) => {
                    adjustChipSize(1, 0);
                });
                pnlSize.Controls.Add(bwp);
                /* Width- */
                var bwm = new Button()
                {
                    Top = ofsY, Width = 40, Left = bwp.Right + 4, Text = "-"
                };
                bwm.Click += new EventHandler((s, e) => {
                    adjustChipSize(-1, 0);
                });
                pnlSize.Controls.Add(bwm);
                ofsY += bwm.Height + 4;

                var lblH = new Label()
                {
                    Top = ofsY, AutoSize = true, Text = "Height"
                };
                pnlSize.Controls.Add(lblH);
                ofsY += lblH.Height;
                /* Height+ */
                var bhp = new Button()
                {
                    Top = ofsY, Width = 40, Text = "+"
                };
                bhp.Click += new EventHandler((s, e) => {
                    adjustChipSize(0, 1);
                });
                pnlSize.Controls.Add(bhp);
                /* Height- */
                var bhm = new Button()
                {
                    Top = ofsY, Width = 40, Left = bhp.Right + 4, Text = "-"
                };
                bhm.Click += new EventHandler((s, e) => {
                    adjustChipSize(0, -1);
                });
                pnlSize.Controls.Add(bhm);
                /* */
                mPnlV.Controls.Add(pnlSize);
            }

            var pnlButton = new Panel();

            {
                pnlButton.Top      = pnlSize.Bottom;
                pnlButton.AutoSize = true;
                /* OK */
                var okButton = new Button()
                {
                    Text = "OK"
                };
                okButton.Click += new EventHandler((s, e) => {
                    if (mModelNameTextBox != null)
                    {
                        string name = mModelNameTextBox.Text;
                        if (name.Length == 0)
                        {
                            MessageBox.Show("Please enter a model name.");
                            return;
                        }
                        mModel.SetName(CustomCompositeElm.lastModelName = name);
                    }
                    CirSim.Sim.UpdateModels();
                    CirSim.Sim.NeedAnalyze(); /* will get singular matrix if we don't do this */
                    closeDialog();
                });
                pnlButton.Controls.Add(okButton);
                /* */
                mPnlV.Controls.Add(pnlButton);
            }

            mCanvas.MouseDown += new MouseEventHandler((s, e) => { onMouseDown(e); });
            mCanvas.MouseUp   += new MouseEventHandler((s, e) => { onMouseUp(e); });
            mCanvas.MouseMove += new MouseEventHandler((s, e) => { onMouseMove(e); });

            Controls.Add(mPnlV);

            Width  = mCanvas.Width + 16;
            Height = pnlButton.Bottom;

            timer1.Interval = 33;
            timer1.Enabled  = true;
            timer1.Start();
        }
예제 #7
0
파일: Scope.cs 프로젝트: mctr909/CircuitSim
        void _drawCrosshairs(CustomGraphics g)
        {
            if (CirSim.Sim.DialogIsShowing())
            {
                return;
            }
            if (!BoundingBox.Contains(CirSim.Sim.MouseCursorX, CirSim.Sim.MouseCursorY))
            {
                return;
            }
            if (SelectedPlot < 0 && !ShowFFT)
            {
                return;
            }
            var info = new string[4];
            int ipa  = mPlots[0].StartIndex(BoundingBox.Width);
            int ip   = (CirSim.Sim.MouseCursorX - BoundingBox.X + ipa) & (mScopePointCount - 1);
            int ct   = 0;
            int maxy = (BoundingBox.Height - 1) / 2;
            int y    = maxy;

            if (SelectedPlot >= 0)
            {
                var plot = mVisiblePlots[SelectedPlot];
                info[ct++] = plot.GetUnitText(plot.MaxValues[ip]);
                int maxvy = (int)(mMainGridMult * (plot.MaxValues[ip] - mMainGridMid));
                g.LineColor = plot.Color;
                g.FillCircle(CirSim.Sim.MouseCursorX, BoundingBox.Y + y - maxvy, 2.5f);
            }
            if (ShowFFT)
            {
                double maxFrequency = 1 / (ControlPanel.TimeStep * Speed * 2);
                info[ct++] = Utils.UnitText(maxFrequency * (CirSim.Sim.MouseCursorX - BoundingBox.X) / BoundingBox.Width, "Hz");
            }
            if (mVisiblePlots.Count > 0)
            {
                double t = CirSim.Sim.Time - ControlPanel.TimeStep * Speed * (BoundingBox.X + BoundingBox.Width - CirSim.Sim.MouseCursorX);
                info[ct++] = Utils.TimeText(t);
            }

            int szw = 0, szh = 15 * ct;

            for (int i = 0; i != ct; i++)
            {
                int w = (int)g.GetTextSize(info[i]).Width;
                if (w > szw)
                {
                    szw = w;
                }
            }

            g.LineColor = CustomGraphics.WhiteColor;
            g.DrawLine(CirSim.Sim.MouseCursorX, BoundingBox.Y, CirSim.Sim.MouseCursorX, BoundingBox.Y + BoundingBox.Height);

            int bx = CirSim.Sim.MouseCursorX;

            if (bx < szw / 2)
            {
                bx = szw / 2;
            }

            g.LineColor = ControlPanel.ChkPrintable.Checked ? Color.White : Color.Black;
            g.FillRectangle(bx - szw / 2, BoundingBox.Y - szh, szw, szh);

            for (int i = 0; i != ct; i++)
            {
                int w = (int)g.GetTextSize(info[i]).Width;
                g.DrawLeftText(info[i], bx - w / 2, BoundingBox.Y - 2 - (ct - 1 - i) * 15);
            }
        }
예제 #8
0
파일: Scope.cs 프로젝트: mctr909/CircuitSim
        public void Draw(CustomGraphics g)
        {
            if (mPlots.Count == 0)
            {
                return;
            }

            /* reset if timestep changed */
            if (mScopeTimeStep != ControlPanel.TimeStep)
            {
                mScopeTimeStep = ControlPanel.TimeStep;
                ResetGraph();
            }

            _drawSettingsWheel(g);

            g.LineColor = Color.Red;

            g.SetTransform(new Matrix(1, 0, 0, 1, BoundingBox.X, BoundingBox.Y));

            if (ShowFFT)
            {
                _drawFFTVerticalGridLines(g);
                _drawFFT(g);
            }

            if (mMaxScale)
            {
                mScale = 1e-4;
            }
            mReduceRange       = false;
            mSomethingSelected = false;  /* is one of our plots selected? */

            for (int si = 0; si != mVisiblePlots.Count; si++)
            {
                var plot = mVisiblePlots[si];
                _calcPlotScale(plot);
                if (CirSim.Sim.ScopeSelected == -1 && plot.Elm != null && plot.Elm.IsMouseElm)
                {
                    mSomethingSelected = true;
                }
                mReduceRange = true;
            }

            _checkForSelection();
            if (SelectedPlot >= 0)
            {
                mSomethingSelected = true;
            }

            mDrawGridLines = true;
            if ((ShowMax || ShowMin) && mVisiblePlots.Count > 0)
            {
                _calcMaxAndMin();
            }

            if (ShowV)
            {
                /* draw volts on top (last), then current underneath, then everything else */
                for (int i = 0; i != mVisiblePlots.Count; i++)
                {
                    if (i != SelectedPlot)
                    {
                        _drawPlot(g, mVisiblePlots[i], false);
                    }
                }
                /* draw selection on top.  only works if selection chosen from scope */
                if (SelectedPlot >= 0 && SelectedPlot < mVisiblePlots.Count)
                {
                    _drawPlot(g, mVisiblePlots[SelectedPlot], true);
                }
            }

            if (mVisiblePlots.Count > 0)
            {
                _drawInfoTexts(g);
            }

            g.ClearTransform();
            _drawCrosshairs(g);

            g.SetTransform(new Matrix(
                               CirSim.Sim.Transform[0], CirSim.Sim.Transform[1],
                               CirSim.Sim.Transform[2], CirSim.Sim.Transform[3],
                               CirSim.Sim.Transform[4], CirSim.Sim.Transform[5]
                               ));

            if (5 < mPlots[0].Pointer && !LockScale)
            {
                if (1e-4 < mScale && mReduceRange)
                {
                    mScale /= 2;
                }
            }
        }
예제 #9
0
파일: Scope.cs 프로젝트: mctr909/CircuitSim
        /* calc frequency if possible and display it */
        void _drawFrequency(CustomGraphics g)
        {
            /* try to get frequency
             * get average */
            double avg = 0;
            int    i;
            var    plot = mVisiblePlots[0];
            int    ipa  = plot.Pointer + mScopePointCount - BoundingBox.Width;
            var    minV = plot.MinValues;
            var    maxV = plot.MaxValues;

            for (i = 0; i != BoundingBox.Width; i++)
            {
                int ip = (i + ipa) & (mScopePointCount - 1);
                avg += minV[ip] + maxV[ip];
            }
            avg /= i * 2;
            int    state     = 0;
            double thresh    = avg * .05;
            int    oi        = 0;
            double avperiod  = 0;
            int    periodct  = -1;
            double avperiod2 = 0;

            /* count period lengths */
            for (i = 0; i != BoundingBox.Width; i++)
            {
                int    ip = (i + ipa) & (mScopePointCount - 1);
                double q  = maxV[ip] - avg;
                int    os = state;
                if (q < thresh)
                {
                    state = 1;
                }
                else if (q > -thresh)
                {
                    state = 2;
                }
                if (state == 2 && os == 1)
                {
                    int pd = i - oi;
                    oi = i;
                    /* short periods can't be counted properly */
                    if (pd < 12)
                    {
                        continue;
                    }
                    /* skip first period, it might be too short */
                    if (periodct >= 0)
                    {
                        avperiod  += pd;
                        avperiod2 += pd * pd;
                    }
                    periodct++;
                }
            }
            avperiod  /= periodct;
            avperiod2 /= periodct;
            double periodstd = Math.Sqrt(avperiod2 - avperiod * avperiod);
            double freq      = 1 / (avperiod * ControlPanel.TimeStep * Speed);

            /* don't show freq if standard deviation is too great */
            if (periodct < 1 || periodstd > 2)
            {
                freq = 0;
            }
            /* Console.WriteLine(freq + " " + periodstd + " " + periodct); */
            if (freq != 0)
            {
                _drawInfoText(g, Utils.UnitText(freq, "Hz"));
            }
        }
예제 #10
0
파일: Scope.cs 프로젝트: mctr909/CircuitSim
        /* calc RMS and display it */
        void _drawRMS(CustomGraphics g)
        {
            var    plot = mVisiblePlots[0];
            int    i;
            double avg   = 0;
            int    ipa   = plot.Pointer + mScopePointCount - BoundingBox.Width;
            var    maxV  = plot.MaxValues;
            var    minV  = plot.MinValues;
            double mid   = (mMaxValue + mMinValue) / 2;
            int    state = -1;

            /* skip zeroes */
            for (i = 0; i != BoundingBox.Width; i++)
            {
                int ip = (i + ipa) & (mScopePointCount - 1);
                if (maxV[ip] != 0)
                {
                    if (maxV[ip] > mid)
                    {
                        state = 1;
                    }
                    break;
                }
            }
            int    firstState = -state;
            int    start      = i;
            int    end        = 0;
            int    waveCount  = 0;
            double endAvg     = 0;

            for (; i != BoundingBox.Width; i++)
            {
                int  ip = (i + ipa) & (mScopePointCount - 1);
                bool sw = false;

                /* switching polarity? */
                if (state == 1)
                {
                    if (maxV[ip] < mid)
                    {
                        sw = true;
                    }
                }
                else if (minV[ip] > mid)
                {
                    sw = true;
                }

                if (sw)
                {
                    state = -state;
                    /* completed a full cycle? */
                    if (firstState == state)
                    {
                        if (waveCount == 0)
                        {
                            start      = i;
                            firstState = state;
                            avg        = 0;
                        }
                        waveCount++;
                        end    = i;
                        endAvg = avg;
                    }
                }
                if (waveCount > 0)
                {
                    double m = (maxV[ip] + minV[ip]) * .5;
                    avg += m * m;
                }
            }
            double rms;

            if (waveCount > 1)
            {
                rms = Math.Sqrt(endAvg / (end - start));
                _drawInfoText(g, plot.GetUnitText(rms) + "rms");
            }
        }
예제 #11
0
파일: Scope.cs 프로젝트: mctr909/CircuitSim
        void _drawFFT(CustomGraphics g)
        {
            if (mFft == null || mFft.Size != mScopePointCount)
            {
                mFft = new FFT(mScopePointCount);
            }
            var real = new double[mScopePointCount];
            var imag = new double[mScopePointCount];
            var plot = (mVisiblePlots.Count == 0) ? mPlots[0] : mVisiblePlots[0];
            var maxV = plot.MaxValues;
            var minV = plot.MinValues;
            int ptr  = plot.Pointer;

            for (int i = 0; i < mScopePointCount; i++)
            {
                int ii = (ptr - i + mScopePointCount) & (mScopePointCount - 1);

                /* need to average max and min or else it could cause average of function to be > 0, which
                 * /* produces spike at 0 Hz that hides rest of spectrum */
                real[i] = .5 * (maxV[ii] + minV[ii]);
                imag[i] = 0;
            }
            mFft.Exec(real, imag);
            double maxM = 1e-8;

            for (int i = 0; i < mScopePointCount / 2; i++)
            {
                double m = mFft.Magnitude(real[i], imag[i]);
                if (m > maxM)
                {
                    maxM = m;
                }
            }
            int prevX = 0;

            g.LineColor = Color.Red;
            if (!LogSpectrum)
            {
                int prevHeight = 0;
                int y          = (BoundingBox.Height - 1) - 12;
                for (int i = 0; i < mScopePointCount / 2; i++)
                {
                    int x = 2 * i * BoundingBox.Width / mScopePointCount;

                    /* rect.width may be greater than or less than scopePointCount/2,
                     * so x may be greater than or equal to prevX. */
                    double magnitude = mFft.Magnitude(real[i], imag[i]);
                    int    height    = (int)((magnitude * y) / maxM);
                    if (x != prevX)
                    {
                        g.DrawLine(prevX, y - prevHeight, x, y - height);
                    }
                    prevHeight = height;
                    prevX      = x;
                }
            }
            else
            {
                int    y0    = 5;
                int    prevY = 0;
                double ymult = BoundingBox.Height / 10;
                double val0  = mScale * ymult;
                for (int i = 0; i < mScopePointCount / 2; i++)
                {
                    int x = 2 * i * BoundingBox.Width / mScopePointCount;

                    /* rect.width may be greater than or less than scopePointCount/2,
                     * so x may be greater than or equal to prevX. */
                    var mag = mFft.Magnitude(real[i], imag[i]);
                    if (0 == mag)
                    {
                        mag = 1;
                    }
                    double val = Math.Log(mag);
                    int    y   = y0 - (int)(val * ymult - val0);
                    if (x != prevX)
                    {
                        g.DrawLine(prevX, prevY, x, y);
                    }
                    prevY = y;
                    prevX = x;
                }
            }
        }
예제 #12
0
파일: Scope.cs 프로젝트: mctr909/CircuitSim
        void _drawPlot(CustomGraphics g, ScopePlot plot, bool selected)
        {
            if (plot.Elm == null)
            {
                return;
            }
            int i;
            int multptr = 0;
            int x       = 0;
            int maxy    = (BoundingBox.Height - 1) / 2;
            int y       = maxy;

            var color = (mSomethingSelected) ? Color.FromArgb(0xA0, 0xA0, 0xA0) : plot.Color;

            if (selected || (CirSim.Sim.ScopeSelected == -1 && plot.Elm.IsMouseElm))
            {
                color = CustomGraphics.SelectColor;
            }
            else if (ControlPanel.ChkPrintable.Checked)
            {
                color = CustomGraphics.GrayColor;
            }

            var ipa     = plot.StartIndex(BoundingBox.Width);
            var maxV    = plot.MaxValues;
            var minV    = plot.MinValues;
            var gridMax = mScale;

            /* if we don't have overlapping scopes of different units, we can move zero around.
             * Put it at the bottom if the scope is never negative. */
            double mx = gridMax;
            double mn = 0;

            if (mMaxScale)
            {
                /* scale is maxed out, so fix boundaries of scope at maximum and minimum. */
                mx = mMaxValue;
                mn = mMinValue;
            }
            else if (mShowNegative || mMinValue < (mx + mn) * .5 - (mx - mn) * .55)
            {
                mn            = -gridMax;
                mShowNegative = true;
            }
            var gridMid = (mx + mn) * .5;

            gridMax = (mx - mn) * .55;  /* leave space at top and bottom */

            double gridMult = maxy / gridMax;

            if (selected)
            {
                mMainGridMult = gridMult;
                mMainGridMid  = gridMid;
            }
            int minRangeLo = -10 - (int)(gridMid * gridMult);
            int minRangeHi = 10 - (int)(gridMid * gridMult);

            mGridStepY = 1e-8;
            while (mGridStepY < 20 * gridMax / maxy)
            {
                mGridStepY *= MULTA[(multptr++) % 3];
            }

            /* Horizontal gridlines */
            int ll;
            var minorDiv = Color.FromArgb(0x30, 0x30, 0x30);
            var majorDiv = Color.FromArgb(0xA0, 0xA0, 0xA0);

            if (ControlPanel.ChkPrintable.Checked)
            {
                minorDiv = Color.FromArgb(0xD0, 0xD0, 0xD0);
                majorDiv = Color.FromArgb(0x80, 0x80, 0x80);
            }

            /* Vertical (T) gridlines */
            double ts = ControlPanel.TimeStep * Speed;

            mGridStepX = CalcGridStepX();

            if (mDrawGridLines)
            {
                /* horizontal gridlines */

                /* don't show gridlines if lines are too close together (except for center line) */
                bool showGridLines = (mGridStepY != 0);
                for (ll = -100; ll <= 100; ll++)
                {
                    if (ll != 0 && !showGridLines)
                    {
                        continue;
                    }
                    int yl = maxy - (int)((ll * mGridStepY - gridMid) * gridMult);
                    if (yl < 0 || yl >= BoundingBox.Height - 1)
                    {
                        continue;
                    }
                    g.LineColor = ll == 0 ? majorDiv : minorDiv;
                    g.DrawLine(0, yl, BoundingBox.Width - 1, yl);
                }

                /* vertical gridlines */
                double tstart = CirSim.Sim.Time - ControlPanel.TimeStep * Speed * BoundingBox.Width;
                double tx     = CirSim.Sim.Time - (CirSim.Sim.Time % mGridStepX);

                for (ll = 0; ; ll++)
                {
                    double tl = tx - mGridStepX * ll;
                    int    gx = (int)((tl - tstart) / ts);
                    if (gx < 0)
                    {
                        break;
                    }
                    if (gx >= BoundingBox.Width)
                    {
                        continue;
                    }
                    if (tl < 0)
                    {
                        continue;
                    }
                    if (((tl + mGridStepX / 4) % (mGridStepX * 10)) < mGridStepX)
                    {
                        g.LineColor = majorDiv;
                    }
                    else
                    {
                        g.LineColor = minorDiv;
                    }
                    g.DrawLine(gx, 0, gx, BoundingBox.Height - 1);
                }
            }

            /* only need gridlines drawn once */
            mDrawGridLines = false;

            g.LineColor = color;
            int ox = -1;
            int oy = -1;

            for (i = 0; i != BoundingBox.Width; i++)
            {
                int nx    = x + i;
                int ip    = (i + ipa) & (mScopePointCount - 1);
                int minvy = (int)(gridMult * (minV[ip] - gridMid));
                int maxvy = (int)(gridMult * (maxV[ip] - gridMid));
                if (minvy <= maxy)
                {
                    if (minvy < minRangeLo || maxvy > minRangeHi)
                    {
                        /* we got a value outside min range, so we don't need to rescale later */
                        mReduceRange = false;
                        minRangeLo   = -1000;
                        minRangeHi   = 1000; /* avoid triggering this test again */
                    }
                    if (ox != -1)
                    {
                        if (minvy == oy && maxvy == oy)
                        {
                            continue;
                        }
                        g.DrawLine(ox, y - oy, nx, y - oy);
                        ox = oy = -1;
                    }
                    if (minvy == maxvy)
                    {
                        ox = nx;
                        oy = minvy;
                        continue;
                    }
                    g.DrawLine(nx, y - minvy, nx, y - maxvy);
                }
            } /* for (i=0...) */
            if (ox != -1)
            {
                g.DrawLine(ox, y - oy, x + i, y - oy); /* Horizontal */
            }
        }