2012-06-05 5 views
9

내 C# WinForms 응용 프로그램에는 전압/전류 측정 결과 인 2 개의 곡선을 호스트하는 그림 상자가 있습니다. X 축은 전압이고 Y 축은 전류입니다. 전압 축은 -5에서 5까지의 범위이지만 현재 축은 -10 uA에서 10 uA 범위의 훨씬 작은 범위입니다. 작업은 두 번째 곡선이 첫 번째 곡선의 10 % 내에 있는지 확인하는 것입니다.커브 주위에 봉투 그리기

시각적 인 검사를 위해 첫 번째 곡선 (파란색) 주위에 봉투를 그립니다. 곡선은 단지 PointF 배열입니다. 파란색 곡선 주위에 올바른 엔벨로프를 그리는 방법을 모르는 순간부터, 실제 곡선의 X 점을 더하고 원래 곡선의 10 %를 뺀 두 개의 다른 곡선을 그립니다. 물론 이것은 나쁜 접근 방법이지만, 수직적 인 커브 구간에 있어서는 적어도 작동합니다.

여기 enter image description here

내가 봉투를 그릴 사용하고있는 코드입니다 : 아래 그림에서 볼 수하지만 즉시 곡선이 아닌 수직 단면에,이 트릭은 더 이상 작동하지 않습니다 :

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; 
} 

녹색 원이 자신에 의해 첨가하고, 그들은 제 곡선 (레드 하나) 잠재적 인 orginal 한 곡선에서의 차이보다 더 큰 10 %를 가지는 영역을 나타낸다.

누군가 나를 올바른 방법으로 넣는다면 좋을 것입니다. 원래 곡선 주위에 멋진 봉투를 채우려면 어떻게해야합니까?

UPDATE 나는 내가 지금까지이 질문에 주어진 답을 구현하는 방법을 찾을 수 없습니다 멍청한 놈, 그래서 somone에 친절하게 나에게이 문제에 대한이어야 코딩 방식을 표시 할 수 있는지 확인하기 위해 현상금을 넣어하고 있기 때문에.

+2

봉투는 ± 10 % 영역을 의미합니까? 그렇다면, 당신이 필요로하는 첫 번째 일은 실제로 "10 % 이내"가 의미하는 바에 대한보다 명확한 것이라고 생각합니다. 각 전압에서 10 % 이내의 전류? 각 전류에서 10 % 이내의 전압? 다른 것? 이것이 학교/대학 과제에서 오는 것이라면, 실제 문구는 무엇입니까? 비즈니스 목적으로 수행하는 것이라면 기본 요구 사항은 무엇입니까? 그 것이 확실해지면 "봉투"가 어떻게 보이는지 훨씬 명확해질 것입니다. –

+2

원본 커브를 다시 플롯 할 수없고 선 두께를 매우 크게하고 불투명도를 낮출 수 있습니까? – Dan

+0

@Dan 나는 더 큰 펜으로 원래의 커브를 만들려고 이미 시도해 왔지만, 지금하는 것보다 결과가 더 나 빠진다는 것은 나쁜 생각입니다. –

답변

1

가장 좋은 방법은 포인트 배열을 반복하고 매번 두 개의 연속 점에 수직 벡터를 계산하는 것입니다 (구현 단서는 Calculating a 2D Vector's Cross Product 참조). 이 수직 벡터를 따라 어느 방향으로나 투영하여 봉투의 두 점 배열을 생성합니다.(한 지점 수가 높은 및 오프셋으로 그려 때 확인을 보일 것 너무 작지 않다)이 기능은 약 세그먼트의 중간 점을 사용하여 생성

:

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)); 
      } 
     } 
+0

감사합니다. 이것은 내가 원하는 것에 조금 가깝습니다. –

3

점의 각 쌍 사이에 그라디언트를 찾고 중간 점을 통과하는 직교에있는 두 점을 계산해보십시오.

그런 다음 봉투를 그리는 데 사용할 수있는 지점 집합으로 정의 된 두 줄이 더 늘어납니다.

+0

내가해야 할 일을 볼 수 있도록 약간의 코드를 제공해 주시겠습니까? –

1

모두 봉투의 크기를 원하는 방식에 따라 다릅니다.

다음 포인트로 기울기를 계산하고 이전 포인트로 기울기를 계산하고이를 평균 한 다음 기울기에 수직 벡터를 계산하여 각 포인트에서 곡선의 기울기를 계산할 수 있습니다.

이 벡터를 곡선 지점에 추가하십시오. 이렇게하면 봉투의 오른쪽 가장자리가 생깁니다.

커브 점에서이 벡터를 뺍니다. 이것은 당신에게 봉투의 왼쪽 가장자리를 제공합니다.

포인트가 너무 멀리 떨어져 있거나 포인트가 갑자기 변경되면이 메소드는 실패합니다.

+0

흠 ... 나는 니콜라스가 똑같은 생각을 한 것을 눈치 챘다. –

+0

@ 팁 주셔서 감사합니다. 코드가 어떻게 보이는지 볼 기회가 있습니까? 최소한 일부 데이터 포인트는? –

+0

봉투를 어떻게 그려야하는지 알고 싶습니다. –

0

이 아마 바보 같은 제안입니다. 아마도 직접 봉투를 그리는 대신 winforms가 당신을 위해 그것을 할 수 있습니다. 너비가 더 큰 펜을 사용하여 봉투를 선으로 그려보십시오. 아마 그것은 작동 할지도 모른다.

펜 너비를 변경하는 경우이 msdn 예제를 보면 무슨 뜻인지 알 수 있습니다.

http://msdn.microsoft.com/en-us/library/3bssbs7z.aspx