在曲线周围绘制一个信封

Sae*_*ani 9 c# math winforms

在我的C#WinForms应用程序中,我有一个托管2条曲线的图片框(由电压/电流测量引起).X轴是电压,Y轴是电流.电压轴的范围为-5到5,但电流轴的范围小得多,范围从-10 uA到10 uA.任务是查看第二条曲线是否在第一条曲线的10%范围内.

为了目视检查,我试图围绕第一条曲线绘制一个信封(蓝色).曲线只是一个PointF数组.目前因为我不知道如何在蓝色曲线周围绘制一个正确的包络线,我只绘制了另外两条曲线,这些曲线是实际曲线的X点加上并减去原始曲线的10%.当然这是一个糟糕的方法,但至少曲线的部分是明显垂直的,它起作用.但是一旦曲线处于非垂直部分,这个技巧就不再起作用了,如下图所示:

在此输入图像描述

这是我用来绘制信封的代码:

public Bitmap DrawEnvelope(double[,] pinData, float vLimit, float iLimit)
{
    g = Graphics.FromImage(box);
    g.SmoothingMode = SmoothingMode.AntiAlias;
    g.PixelOffsetMode = PixelOffsetMode.HighQuality;

    PointF[] u = new PointF[pinData.GetLength(0)]; //Up line
    PointF[] d = new PointF[pinData.GetLength(0)]; //Down Line
    List<PointF> joinedCurves = new List<PointF>();

    float posX = xMaxValue * (vLimit / 100);
    float minX = posX * -1;


    for (int i = 0; i < pinData.GetLength(0); i++)
    {
        u[i] = new PointF(400 * (1 + (((float)pinData[i, 0]) + minX) / (xMaxValue + vExpand)), 400 * (1 - ((float)pinData[i, 1] * GetInvers((yMaxValue + iExpand)))));
    }

    for (int i = 0; i < pinData.GetLength(0); i++)
    {
        d[i] = new PointF(400 * (1 + (((float)pinData[i, 0]) + posX) / (xMaxValue + vExpand)), 400 * (1 - ((float)pinData[i, 1] * GetInvers((yMaxValue + iExpand)))));
    }


    Pen pengraph = new Pen(Color.FromArgb(50, 0 ,0 ,200), 1F);
    pengraph.Alignment = PenAlignment.Center;

    joinedCurves.AddRange(u);
    joinedCurves.AddRange(d.Reverse());

    PointF[] fillPoints = joinedCurves.ToArray();
    SolidBrush fillBrush = new SolidBrush(Color.FromArgb(40, 0, 0, 250));
    FillMode newFillMode = FillMode.Alternate;

    g.FillClosedCurve(fillBrush, fillPoints, newFillMode, 0);

    g.Dispose();
    return box;
}
Run Code Online (Sandbox Code Playgroud)

绿色圆圈由我自己添加,它们表示第二条曲线(红色曲线)可能与原始曲线的差异大于10%的区域.

如果有人以正确的方式把我放在一边会很好,我应该在原始曲线周围找到一个漂亮的信封?

更新 因为我是如此的诺布,我无法找到一种方法来实现这个问题的答案直到现在,所以请一个赏金,看看somone是否可以告诉我至少一个编码方法来解决这个问题.

zeF*_*chy 1

最好的选择是迭代点数组并每次计算两个连续点的垂直向量(有关实现线索,请参阅计算 2D 向量的叉积)。沿着这些垂直向量向任一方向投影以生成包络的两个点阵列。

该函数大致使用线段中点生成它们(只要点数很高并且偏移量不太小,绘制时看起来应该没问题):

private void GetEnvelope(PointF[] curve, out PointF[] left, out PointF[] right, float offset)
        {
            left = new PointF[curve.Length - 1];
            right = new PointF[curve.Length - 1];

            for (int i = 1; i < curve.Length; i++)
            {
                PointF normal = new PointF(curve[i].Y - curve[i - 1].Y, curve[i - 1].X - curve[i].X);
                float length = (float)Math.Sqrt(normal.X * normal.X + normal.Y * normal.Y);
                normal.X /= length;
                normal.Y /= length;

                PointF midpoint = new PointF((curve[i - 1].X + curve[i].X) / 2F, (curve[i - 1].Y + curve[i].Y) / 2F);
                left[i - 1] = new PointF(midpoint.X - (normal.X * offset), midpoint.Y - (normal.Y * offset));
                right[i - 1] = new PointF(midpoint.X + (normal.X * offset), midpoint.Y + (normal.Y * offset));
            }
        }
Run Code Online (Sandbox Code Playgroud)