ecgdraw.cs
来自「ecg tool kit for medical image retrieval」· CS 代码 · 共 1,206 行 · 第 1/4 页
CS
1,206 行
nMaxY = nMinY + (int) Math.Round(fGridY * nBoxesY),
nAlternate = 1;
if ((nMaxX > myGraphics.VisibleClipBounds.Width)
|| (nMaxY > myGraphics.VisibleClipBounds.Height))
return false;
if (DisplayGrid == GridType.None)
return true;
Pen gridPen = new Pen(GraphColor, fPenWidth >= 1.0f ? fPenWidth : 1.0f),
gridSecondPen = new Pen(GraphSecondColor, fPenWidth >= 1.0f ? fPenWidth : 1.0f);
Brush gridBrush = null;
if ((DisplayGrid == GridType.OneMillimeters)
&& (fGridX >= 10f)
&& (fGridY >= 10f))
{
fGridX /= 5;
fGridY /= 5;
nAlternate = 5;
}
else if (DisplayGrid == GridType.OneMillimeters)
{
gridBrush = new HatchBrush(HatchStyle.Percent30, GraphSecondColor, BackColor);
}
if (gridBrush != null)
myGraphics.FillRectangle(gridBrush, nMinX, nMinY, nMaxX, nMaxY);
int j = 0;
// draw vertical lines.
for (float i=nMinX;i <= (nMaxX + fPenWidth);i+=fGridX,j++)
{
int nTempX = (int) Math.Round(i);
myGraphics.DrawLine((j % nAlternate) == 0 ? gridPen : gridSecondPen, nTempX, nMinY, nTempX, nMaxY);
}
j = 0;
// draw horizontal lines.
for (float i=nMinY;i <= (nMaxY + fPenWidth);i+=fGridY,j++)
{
int nTempY = (int) Math.Round(i);
myGraphics.DrawLine((j % nAlternate) == 0 ? gridPen : gridSecondPen, nMinX, nTempY, nMaxX, nTempY);
}
if (gridBrush != null)
gridBrush.Dispose();
gridPen.Dispose();
gridSecondPen.Dispose();
return true;
}
/// <summary>
/// Function that will draw as much signal on the image as possible.
/// </summary>
/// <param name="myGraphics">The drawing surface.</param>
/// <param name="signals">signal data.</param>
/// <param name="dtRecordTime">Recording time of signal.</param>
/// <param name="bShowTime">true if need to show the time</param>
/// <param name="nTime">Sample number to start drawing of signal,</param>
/// <param name="fmm_Per_s">mm per second</param>
/// <param name="fmm_Per_mV">mm per mV</param>
/// <param name="nMinX">minimal X value to draw.</param>
/// <param name="nMinY">minimal Y value to draw.</param>
/// <param name="nMaxX">maximum X value to draw.</param>
/// <param name="nMaxY">maximum Y value to draw.</param>
/// <param name="fPixel_Per_s">pixels per second.</param>
/// <param name="fPixel_Per_uV">pixels per uV.</param>
/// <param name="fLeadYSpace">space for each lead.</param>
/// <param name="bAllowResample">True if resample of signal is allowed.</param>
/// <returns>Sample number to start next draw ECG on.</returns>
private static int DrawSignal(Graphics myGraphics, ECGSignals.Signals signals, DateTime dtRecordTime, bool bShowTime, int nTime, float fmm_Per_s, float fmm_Per_mV, int nMinX, int nMinY, int nMaxX, int nMaxY, float fPixel_Per_s, float fPixel_Per_uV, float fLeadYSpace, bool bAllowResample)
{
float fGridY = (DpiY * Inch_Per_mm) * _mm_Per_GridLine;
int nOldRhythmSamplesPerSecond = 0;
// begin: resample signals to fit. (using a dirty solution)
if (signals.RhythmSamplesPerSecond != (int) fPixel_Per_s)
{
if (!bAllowResample)
{
nOldRhythmSamplesPerSecond = signals.RhythmSamplesPerSecond;
signals = signals.Clone();
}
// You should note that if signal is already resampled, but dpi changes the new signal
// will be resampled based on already resampled information instead of reloading from
// orignal.
int RI = ECGConversion.ECGTool.ResampleInterval;
ECGConversion.ECGTool.ResampleInterval /= DirtSolutionFactor;
for (int i=0;i < signals.NrLeads;i++)
{
ECGTool.ResampleLead(signals[i].Rhythm, (int) signals.RhythmSamplesPerSecond * DirtSolutionFactor, (int) (fPixel_Per_s * DirtSolutionFactor), out signals[i].Rhythm);
if ((signals.MedianSamplesPerSecond != 0)
&& (signals[i].Median != null))
ECGTool.ResampleLead(signals[i].Median, (int) signals.MedianSamplesPerSecond * DirtSolutionFactor, (int) (fPixel_Per_s * DirtSolutionFactor), out signals[i].Median);
signals[i].RhythmStart = (signals[i].RhythmStart * (int) (fPixel_Per_s * DirtSolutionFactor)) / (int) (signals.RhythmSamplesPerSecond * DirtSolutionFactor);
signals[i].RhythmEnd = (signals[i].RhythmEnd * (int) (fPixel_Per_s * DirtSolutionFactor)) / (int) (signals.RhythmSamplesPerSecond * DirtSolutionFactor);
}
ECGConversion.ECGTool.ResampleInterval = RI;
nTime = (nTime * (int) (fPixel_Per_s * DirtSolutionFactor)) / (int) (signals.RhythmSamplesPerSecond * DirtSolutionFactor);
// set new rhythm per samples.
signals.RhythmSamplesPerSecond = (int) fPixel_Per_s;
if (signals.MedianSamplesPerSecond != 0)
signals.MedianSamplesPerSecond = (int) fPixel_Per_s;
}
// end: resample signals to fit. (dirty solution)
// begin: find start and end.
int nStart = int.MaxValue,
nEnd = int.MinValue;
for (int lead=0;lead < signals.NrLeads;lead++)
{
if (signals[lead] != null)
{
nStart = Math.Min(nStart, signals[lead].RhythmStart);
nEnd = Math.Max(nEnd, signals[lead].RhythmEnd);
}
}
// end: find start and end.
int nPulseSpace = (int) Math.Floor(DpiX * Inch_Per_mm * _mm_Per_GridLine) + 1;
nStart += nTime;
int nXOffset = nMinX;
float fYOffset = nMinY;
DrawLeadHead(myGraphics, signals, dtRecordTime, bShowTime, nTime, nMinX, fYOffset, nMaxX, fmm_Per_s, fmm_Per_mV, fPixel_Per_uV, fLeadYSpace, nPulseSpace, nMinY);
Pen myPen = new Pen(SignalColor);
// begin: write rhythm data to image
for (int n=nTime+1;n <= nEnd;n++)
{
for (byte i=0;i < signals.NrLeads;i++)
{
int x1 = n - nStart - 1 + nPulseSpace + nXOffset,
x2 = n - nStart + nPulseSpace + nXOffset;
short
y1 = short.MinValue,
y2 = short.MinValue;
if (x2 > nMaxX)
{
// check whether there is space for drawing leads below
if ((int) (fYOffset + ((signals.NrLeads * fLeadYSpace + fGridY) * 2)) < nMaxY)
{
nXOffset -= nMaxX - nMinX - nPulseSpace;
fYOffset += signals.NrLeads * fLeadYSpace + nMinY + fGridY;
x1 = n - nStart - 1 + nPulseSpace + nXOffset;
x2 = n - nStart + nPulseSpace + nXOffset;
DrawLeadHead(myGraphics, signals, dtRecordTime, bShowTime, n-1, nMinX, fYOffset, nMaxX, fmm_Per_s, fmm_Per_mV, fPixel_Per_uV, fLeadYSpace, nPulseSpace, nMinY);
}
else
{
// no more space so end drawing.
nEnd = n - 1;
break;
}
}
if ((n > signals[i].RhythmStart)
&& (n <= signals[i].RhythmEnd))
{
y1 = signals[i].Rhythm[n-1-signals[i].RhythmStart];
y2 = signals[i].Rhythm[n-signals[i].RhythmStart];
}
if ((y1 != short.MinValue)
&& (y2 != short.MinValue))
myGraphics.DrawLine(
myPen,
x1,
(float) (((i + .5f) * fLeadYSpace) + fGridY - (y1 * signals.RhythmAVM * fPixel_Per_uV) + fYOffset),
x2,
(float) (((i + .5f) * fLeadYSpace) + fGridY - (y2 * signals.RhythmAVM * fPixel_Per_uV) + fYOffset));
}
}
// end: write rhythm data to image
if (nOldRhythmSamplesPerSecond != 0)
{
nEnd = (int) (((long) nEnd * nOldRhythmSamplesPerSecond) / signals.RhythmSamplesPerSecond);
}
myPen.Dispose();
return nEnd;
}
/// <summary>
/// Function to draw the head of a signal.
/// </summary>
/// <param name="myGraphics">The drawing surface.</param>
/// <param name="signals">signal data</param>
/// <param name="dtRecordTime">start time of recording</param>
/// <param name="bShowTime">true if need to show time</param>
/// <param name="nTime">sample number currently add.</param>
/// <param name="nX">x position in image</param>
/// <param name="fY">y position in image</param>
/// <param name="nMaxX">maximum x value</param>
/// <param name="fmm_Per_s">mm per second</param>
/// <param name="fmm_Per_mV">mm per mV</param>
/// <param name="fPixel_Per_uV">Pixels per uV</param>
/// <param name="fLeadYSpace">Space for lead in Y axe.</param>
/// <param name="nPulseSpace">Space for the calibration pulse (in pixels)</param>
/// <param name="nExtraSpace">Space for text (in pixels)</param>
private static void DrawLeadHead(Graphics myGraphics, ECGSignals.Signals signals, DateTime dtRecordTime, bool bShowTime, int nTime, int nX, float fY, int nMaxX, float fmm_Per_s, float fmm_Per_mV, float fPixel_Per_uV, float fLeadYSpace, int nPulseSpace, int nExtraSpace)
{
int nY = (int) Math.Round(fY);
// begin: write tags per lead.
Font fontText = new Font("Verdana", _TextSize);
SolidBrush solidBrush = new SolidBrush(TextColor);
long lTime = (nTime * 1000) / signals.RhythmSamplesPerSecond;
DateTime dtTemp = dtRecordTime.AddMilliseconds(lTime);
if (bShowTime)
{
myGraphics.DrawString(
((dtTemp.Year > 100)
? dtTemp.ToShortDateString() + " "
: "")
+ dtTemp.Hour.ToString("00") + ":"
+ dtTemp.Minute.ToString("00") + ":"
+ dtTemp.Second.ToString("00") + "."
+ (dtTemp.Millisecond/100).ToString("0"),
fontText,
solidBrush,
nX,
nY - nExtraSpace);
}
if (DisplayInfo)
{
string tempInfo = fmm_Per_s + "mm/s, " + fmm_Per_mV + "mm/mV";
myGraphics.DrawString(
tempInfo,
fontText,
solidBrush,
nMaxX - myGraphics.MeasureString(tempInfo, fontText).Width,
nY - nExtraSpace);
}
nY = (int) Math.Round(fY + (DpiY * Inch_Per_mm * _mm_Per_GridLine));
for (byte i=0;i < signals.NrLeads;i++)
myGraphics.DrawString(
(signals[i].Type != ECGConversion.ECGSignals.LeadType.Unknown
? signals[i].Type.ToString()
: "Channel " + (i + 1)),
fontText,
solidBrush,
nX + nPulseSpace + 2.0f ,
nY + 2.0f + i * fLeadYSpace);
fontText.Dispose();
fontText = new Font("System", _TextSize);
fontText.Dispose();
solidBrush.Dispose();
// end: write tags per lead.
// begin: draw pulse.
Pen myPen = new Pen(SignalColor);
for (int i=0;i < signals.NrLeads;i++)
{
int a = ((nPulseSpace << 1) / 3) + nX,
b = (int) Math.Round(((i + .5f) * fLeadYSpace) - (1000.0f * fPixel_Per_uV)) + nY,
c = (int) Math.Round((i + .5f) * fLeadYSpace) + nY;
myGraphics.DrawLine(myPen, a, c, a, b);
myGraphics.DrawLine(myPen, a, b, nPulseSpace + nX, b);
myGraphics.DrawLine(myPen, nPulseSpace + nX, c, nPulseSpace + nX, b);
}
myPen.Dispose();
// end: draw pulse.
}
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?