void _allocImage() { if (mContext == null) { mContext = CustomGraphics.FromImage(BoundingBox.Width, BoundingBox.Height); } }
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(); } }
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); } }
void _drawInfoText(CustomGraphics g, string text) { if (BoundingBox.Y + BoundingBox.Height <= mTextY + 5) { return; } g.DrawLeftText(text, 0, mTextY); mTextY += 15; }
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(); }
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); } }
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; } } }
/* 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")); } }
/* 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"); } }
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; } } }
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 */ } }