2012-06-05 30 views
9

En mi aplicación C# WinForms tengo un cuadro de imagen que aloja 2 curvas (resultado de una medición de voltaje/corriente). El eje X es voltaje y el eje Y es actual. El eje de voltaje varía de -5 a 5, pero el eje actual es una escala mucho más pequeña que va de -10 uA a 10 uA. La tarea es ver si la segunda curva está dentro del 10% de la primera curva.Dibujar un sobre alrededor de una curva

Para la inspección visual, estoy tratando de dibujar un sobre alrededor de la primera curva (Azul uno). La curva es solo una matriz PointF. Por el momento, dado que no tengo idea de cómo dibujar una envolvente correcta alrededor de la curva azul, simplemente dibujo otras dos curvas que son el resultado de X puntos de la curva real añadida y restados en un 10% de la curva original. Por supuesto, este es un mal enfoque, pero al menos para la sección de la curva que es notoriamente vertical, funciona. Pero tan pronto como la curva está en su sección no vertical, este truco ya no funciona, como se puede ver en la imagen siguiente:

enter image description here

Aquí está el código que estoy usando para sacar el sobre :

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

los círculos verdes se añaden por mí mismo, y que indican la región que la segunda curva (una roja) es potencialmente tiene una diferencia más grande que 10% a partir de la curva original.

Sería bueno si alguien me pusiera en el camino correcto, ¿qué debo buscar para lograr un bonito sobre la curva original?

ACTUALIZACIÓN porque soy muy Noob no puedo encontrar una manera de poner en práctica las respuestas dadas a esta pregunta hasta ahora, para poner una recompensa para ver si somone amablemente me puede mostrar al menos un método de codificación para este problema.

+2

es la envolvente destinado a ser el + - región de 10%? Si es así, entonces creo que lo primero que necesita es más precisión sobre lo que realmente significa "dentro del 10%". Corriente dentro de 10% en cada voltaje? Voltaje dentro del 10% en cada corriente? ¿Alguna otra cosa? Si esto proviene de una asignación de escuela/universidad, ¿cuál fue la redacción actual? Si es algo que está haciendo por razones comerciales, ¿cuáles son los requisitos subyacentes? Una vez que está claro, probablemente será mucho más claro cómo debería ser su "sobre". –

+2

¿No puede trazar su curva original otra vez, hacer que el grosor de línea sea muy grande y la opacidad baja? – Dan

+0

@Dan Ya he intentado hacer la curva original con un bolígrafo más grande, pero es una mala idea que el resultado sea peor que lo que estoy haciendo ahora. –

Respuesta

1

Su mejor opción es iterar su matriz de puntos y calcular un vector perpendicular en dos puntos consecutivos cada vez (consulte Calculating a 2D Vector's Cross Product para conocer las pistas de implementación). Proyecte en cualquier dirección a lo largo de estos vectores perpendiculares para generar los dos conjuntos de puntos de su envolvente.

Esta función les genera más o menos usando puntos medios de segmentos (siempre y cuando el número de puntos es alta y su desplazamiento no es demasiado pequeño que debe ser aceptable cuando se representa):

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

Gracias, este es un poco cerca de lo que quiero. –

3

Puede intentar encontrar el degradado entre cada par de puntos y calcular dos puntos a cada lado que están en el ortogonal que pasa por el punto medio.

A continuación, tendría dos líneas más definidas como un conjunto de puntos que podría utilizar para dibujar el sobre.

+0

¿Puede proporcionar un poco de código para que pueda ver lo que tengo que hacer? –

1

Todo depende de la forma en que desee que se dimensione el sobre.

Puede calcular/estimar la pendiente de la curva en cada punto calculando la pendiente hasta el siguiente punto y la pendiente hasta el punto anterior, promedie estos y luego calcule un vector perpendicular a la pendiente.

Añade este vector al punto de la curva; esto le da el borde derecho del sobre.

Resta este vector del punto de la curva; esto te da el borde izquierdo del sobre.

Este método fallará si los puntos están demasiado separados o si aparecen cambios muy repentinos en los puntos.

+0

Hmmm ... Me acabo de dar cuenta de que Nicholas pensó lo mismo. –

+0

@Gracias por la sugerencia ... ¿hay alguna posibilidad de ver cómo debe ser el código? al menos para algunos de los puntos de datos? –

+0

Necesito saber cómo quiere que se dibuje el sobre. –

0

Esta es probablemente una sugerencia tonta. Tal vez en lugar de dibujar el sobre usted mismo, tal vez podría dejar que winforms lo haga por usted. Intenta dibujar el sobre como una línea con un lápiz que tenga un ancho mayor. Quizás podría funcionar.

Si mira este ejemplo msdn sobre la variación del ancho del lápiz, puede ver lo que quiero decir.

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

Cuestiones relacionadas