none
Dibujar en picturebox: cambiar sentido del eje Y (origen de coordenadas) RRS feed

  • Pregunta

  • Hola,

    querría saber si es posible y cómo se haría par cambiar el origen de coordenadas de coordenadas para dibujar en un picturebox. Por defecto, el origen es en la esquina superior izquierda y me interesaría que fuese en la parte inferior izquierda (como un eje cartesiano normal) es decir, invertir el sentido en el que crece el eje Y, ya que ahora crece hacia "abajo" y querría que fuese hacia "arriba".

    He estado buscando por internet y viendo algunos ejemplos y lo que he visto no me llega a ser del todo útil. Por ejemplo, puedo girarlo x grados con RotateTransform o moverlo x pixels en el eje Y o X con TranslateTransform:

    void frm1_Paint( Object^ /*sender*/, System::Windows::Forms::PaintEventArgs^ e ){
    // Create a local version of the graphics object for the PictureBox.
    Graphics^ g = e->Graphics;
    g->RotateTransform( 180.0F );//gira
    g->TranslateTransform(0.0F, 100.0F, MatrixOrder::Append );//mueve los pixels
    }

    Lo que me interesaría sería invertir solo el eje Y, he visto que también se puede trabajar con matrices, pero los ejemplos que he encontrado no son muy claros. Habría alguna función o propiedad que hiciera esto?

    Gracias de antemano.


    Sara

    • Cambiado RFOGModerator lunes, 5 de marzo de 2012 9:59 (De:Lenguaje C++ y MFC)
    domingo, 4 de marzo de 2012 14:38

Respuestas

  • Te falta establecer la matriz usando la propiedad Transform.

    En el ejemplo yo pinto en el Paint() de un picturebox.

    System::Void pictureBox1_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e) 
    {
    	float base = (float)(pictureBox1->ClientRectangle.Height - 20.0);
    	Matrix ^matriz = gcnew Matrix(1.0, 0.0, 0.0, -1.0, 5.0, base);
    	e->Graphics->Transform = matriz;
    
    	e->Graphics->DrawRectangle(Pens::Red, 5, 5, 50, 150);
    	e->Graphics->DrawRectangle(Pens::Red, 65, 5, 50, 100);
    	e->Graphics->DrawRectangle(Pens::Red, 125, 5, 50, 120);
    	e->Graphics->DrawRectangle(Pens::Red, 185, 5, 50, 70);
    	e->Graphics->DrawLine(Pens::Green, 0.0, 0.0, (float)pictureBox1->ClientRectangle.Width, 0.0); 
    	e->Graphics->DrawLine(Pens::Green, 0.0, 0.0, 0.0, base); 
    }


    • Editado Walter MDV lunes, 5 de marzo de 2012 0:16
    • Marcado como respuesta Sara23SQL lunes, 5 de marzo de 2012 20:26
    lunes, 5 de marzo de 2012 0:12

Todas las respuestas

  • La clase Graphics tiene una propiedad Transform del tipo Matrix del namespace Drawing2D.

    Si no entiendo mal lo que deseas es una matriz 3x3

    1   0    0

    0  -1   0

    0   y   1

    donde y es la altura del rectángulo cliente del picturebox

    matriz(1.0, 0, 0, -1.0, 0, pb->ClientRectangle.Height);

    O sea, un punto en (10, 10), si el pb tiene 200 de alto, lo quieres ver en (10, 190)

    10 * 1 + 0

    10 * (-1) + 200

    No es una rotación, claro. 

    domingo, 4 de marzo de 2012 16:16
  • Eso es, si no hay otra forma de hacerlo, lo haría con matrices, y como dices, no es una rotación ni una traslación (según las funciones que he encontrado) sino cambiar la dirección del eje Y (altura del picturebox), que por defecto, crece hacia abajo. Simplemente haciendo esa función que me indicas (matriz), valdría? Gracias! Voy a probarlo y voy contando.

    Sara

    domingo, 4 de marzo de 2012 19:12
  • Por ejemplo, en la misma Matrix, tienes métodos para hacer la transformación. Digamos, si tienes un arreglo de points, puedes usar VectorTransformPoints() en vez de hacerlo en el Graphics.

    Ok, también puedes pintar el frame fuera del Paint del PB, en un bitmap que luego le es asignado.

     

    domingo, 4 de marzo de 2012 19:47
  • Hola Walter, podrías poner un ejemplo más completo por favor? Es que estoy probando cosillas y no acaba de salir. Creo que es porque me estoy saltando algo y que no lo llego a ver del todo claro. Tengo ahora:

    void frm_Paint( Object^ /*sender*/, System::Windows::Forms::PaintEventArgs^ e ){
       // Create a local version of the graphics object for the PictureBox.
       Graphics^ g = e->Graphics;
       Matrix(1.0, 0, 0, -1.0, 0, pb->ClientRectangle.Height);
       //Me creo una linea vertical para saber en que direccion pinta
       g->DrawLine(System::Drawing::Pens::Red, 25, 0, 25, pb->Height-25);
    }

    Pero sigue pintando de arriba a abajo. Me falta multiplicar, declarar o hacer algo más?

    Gracias!


    Sara

    domingo, 4 de marzo de 2012 23:40
  • Te falta establecer la matriz usando la propiedad Transform.

    En el ejemplo yo pinto en el Paint() de un picturebox.

    System::Void pictureBox1_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e) 
    {
    	float base = (float)(pictureBox1->ClientRectangle.Height - 20.0);
    	Matrix ^matriz = gcnew Matrix(1.0, 0.0, 0.0, -1.0, 5.0, base);
    	e->Graphics->Transform = matriz;
    
    	e->Graphics->DrawRectangle(Pens::Red, 5, 5, 50, 150);
    	e->Graphics->DrawRectangle(Pens::Red, 65, 5, 50, 100);
    	e->Graphics->DrawRectangle(Pens::Red, 125, 5, 50, 120);
    	e->Graphics->DrawRectangle(Pens::Red, 185, 5, 50, 70);
    	e->Graphics->DrawLine(Pens::Green, 0.0, 0.0, (float)pictureBox1->ClientRectangle.Width, 0.0); 
    	e->Graphics->DrawLine(Pens::Green, 0.0, 0.0, 0.0, base); 
    }


    • Editado Walter MDV lunes, 5 de marzo de 2012 0:16
    • Marcado como respuesta Sara23SQL lunes, 5 de marzo de 2012 20:26
    lunes, 5 de marzo de 2012 0:12
  • Sara23SQL, te aconsejo colocar este tipo de preguntas en el foro de Windows Forms, porque aún cuando se refieren a C++, no es el C++ que este foro espera.  Lo que usas ahí es C++/CLI, que es una variante de C++ hecha por Microsoft para facilitar la inclusión de código nativo con código .Net.  Pero en realidad este foro se dedica a C++, el de siempre.  Además, tu pregunta (y preguntas como ésta) puede ser respondida en cualquier lenguaje, incluyendo C# y VB.net.  Eso quiere decir que si preguntas en el foro de Windows Forms, tendrás más expertos viendo tu caso que aquí porque hay más programadores Windows Forms que programadores de C++.

    Si no es molestia, me gustaría mover tu pregunta a ese foro.  Tú me dices.


    Jose R. MCP


    lunes, 5 de marzo de 2012 3:51
    Moderador
  • En el foro de Windows Forms o en de C# no le van a responder porque está preguntando para C++, y la gente de allí, como bien dices, no sabe C++, y menos aún C++/CLI... Además, aquí tenemos un foro de Visual C++ que incluye C++/CLI, que es donde voy a mover yo el hilo.

    Respecto a la pregunta de Sara23SQL, si sólo es cambiar el crecimiento de una de las coordenadas, y te lías con el tema de las transformaciones, lo más sencillo es que calcules a mano la nueva coordenada. Es decir, restes tu valor del máximo Y de la ventana (o de la superficie) en donde estés pintando. Una simple aritmética y te soluciona el problema.

    También tienes algunas funciones nativas para cambiar las "coordenadas del mundo", en concreto SetMapMode() y SetWindowOrgEx(), que creo permiten cambiar el orden de crecimiento de las coordenadas. En principio, pese a que estés pintando con .NET, esos cambios seguirán siendo válidos.


    MVP Visual C++ - Visita mi blog sobre desarrollo: http://geeks.ms/blogs/rfog/

    lunes, 5 de marzo de 2012 9:58
    Moderador
  • Perfecto, gracias! Me faltaba eso. Mi código ha quedado así finalmente:

    void frm_Paint( Object^ /*sender*/, System::Windows::Forms::PaintEventArgs^ e ){
       // Create a local version of the graphics object for the PictureBox.
       Graphics^ g = e->Graphics;
       //Esto es para invertir el eje y
       Matrix ^myMatrix = gcnew Matrix(1.0, 0, 0, -1.0, 0, pb->ClientRectangle.Height);
       g->Transform=myMatrix;
       //Pinta una linea de abajo a arriba
       g->DrawLine(System::Drawing::Pens::Red, 25, 0, 25, pb->Height-25);
    }

    Sara

    lunes, 5 de marzo de 2012 20:25
  • Sara23SQL, te aconsejo colocar este tipo de preguntas en el foro de Windows Forms, porque aún cuando se refieren a C++, no es el C++ que este foro espera.  Lo que usas ahí es C++/CLI, que es una variante de C++ hecha por Microsoft para facilitar la inclusión de código nativo con código .Net.  Pero en realidad este foro se dedica a C++, el de siempre.  Además, tu pregunta (y preguntas como ésta) puede ser respondida en cualquier lenguaje, incluyendo C# y VB.net.  Eso quiere decir que si preguntas en el foro de Windows Forms, tendrás más expertos viendo tu caso que aquí porque hay más programadores Windows Forms que programadores de C++.

    Si no es molestia, me gustaría mover tu pregunta a ese foro.  Tú me dices.


    Jose R. MCP


    Como consideres mejor. Lo puse aquí ya que en el otro foro apenas me contestaban, mientras que en este me han contestado y resuelto mis dudas.

    Saludos!


    Sara

    lunes, 5 de marzo de 2012 20:29