Genere un “pieslice” en C sin usar el pieslice() de graphics.h

9 minutos de lectura

En el encabezado “graphics.h” de la biblioteca BGI hay una función rebanada de pastel en ese archivo de encabezado, su sintaxis es:

#include <graphics.h>

void pieslice(int x, int y, int stangle, int endangle, int radius);

[x,y are the center of the circle,stangle and endangle are the starting and end angles respectively]

¿Podemos hacer un pastel en C/C++ sin usar esta función integrada de la biblioteca BGI? Por favor, ayuda. Intenté hacerlo con la ayuda de los algoritmos de generación de líneas y círculos de punto medio.

Mi código hasta ahora:

#include<stdio.h>
#include<graphics.h>


static const double PI =3.141592

int main()
{
    int gd=DETECT,gm;
    initgraph(&gd,&gm,NULL);
    int xc,yc,r,st_angle,ed_angle,k;
    printf("Enter the centers of pieslice:\n");
    scanf("%d %d",&xc,&yc);
    printf("Enter the radius:\n");
    scanf("%d",&r);
    printf("Enter the starting angle:\n");
    scanf("%d",&st_angle);
    printf("Enter the end angle:\n");
    scanf("%d",&ed_angle);


    for(k=st_angle; k<=ed_angle;k++)
    {   
        double radians =(PI /180.0) * k;
        int X = xc+ cos(radians) * r;
        int Y = yc+ sin(radians) * r;
        putpixel(x,y,WHITE);
        delay(5000);

    }
void wait_for_char()
{

    //Wait for a key press
    int in = 0;

    while (in == 0) {
        in = getchar();
    }
}
getch();
}

Pude hacer la parte del cálculo donde usé la ecuación paramétrica del círculo, pero no pude generar la figura usando el graphics.h función. Un poco de ayuda estaría bien. Gracias de antemano.

Mientras ejecuto este programa, recibo este error:

[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
a.out: ../../src/xcb_io.c:274: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
a.out: ../../src/xcb_io.c:274: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
Aborted (core dumped)


  • No hay ningún intento de dibujar nada en su código.

    – Jabberwocky

    3 oct 2019 a las 15:49


  • @RichardCritten estoy usando el “compilador gcc”[ubuntu 16.0.4]

    usuario10626935

    3 oct 2019 a las 15:52

  • @Jabberwocky “¡No use herramientas que sean más antiguas que usted!” ¡ahora se ha agregado a mi lista de Great Life Quotes! (Junto con cosas como “¡Nunca comas nada más grande que tu cabeza!”)

    – Adrián Mole

    3 oct 2019 a las 15:53

  • @NetranjitBorgohain necesita mostrarnos su código defectuoso. El código en su pregunta no contiene ningún intento de dibujar nada, por lo tanto, no podemos decir qué está mal.

    – Jabberwocky

    3 oct 2019 a las 16:03


  • La función de círculo no funcionará de fábrica porque SOLO hace un círculo. Puede borrar la parte del círculo que no desea dibujar sobre él, pero probablemente esté mejor usando una función de dibujar arco. Una alternativa inferior es volver a implementar la función de círculo y detenerse en parte, lo que da como resultado un arco.

    – usuario4581301

    3 oct 2019 a las 19:12

avatar de usuario
espectro

¿Por qué no usar vectores?

tarta

cuadrado inscrito

Asi que (0,0) pastel centrado de radio r Esta determinado por:

u = (cos(a0),sin(a0))
v = (cos(a1),sin(a1))
x^2 + y^2 <= r^2 // circle
(x,y) x u ->  CW
(x,y) x v -> CCW

el CW/CCW se determina calculando el producto cruzado 3D y examinando el signo de los resultados en la coordenada z…

por lo tanto, procese todos los píxeles en el círculo descrito en el cuadrado y renderice todos los píxeles que cumplan con las 3 condiciones.

Algo como esto:

void pie(int x0,int y0,int r,int a0,int a1,DWORD c)
    {
    // variables
    int  x, y,      // circle centered point
        xx,yy,rr,   // x^2,y^2,r^2
        ux,uy,      // u
        vx,vy,      // v
        sx,sy;      // pixel position
    // my Pixel access (remove these 3 lines)
    int **Pixels=Main->pyx;         // Pixels[y][x]
    int   xs=Main->xs;              // resolution
    int   ys=Main->ys;
    // init variables
    rr=r*r;
    ux=double(r)*cos(double(a0)*M_PI/180.0);
    uy=double(r)*sin(double(a0)*M_PI/180.0);
    vx=double(r)*cos(double(a1)*M_PI/180.0);
    vy=double(r)*sin(double(a1)*M_PI/180.0);
    // render                                       |<-- remove these -->|
    for (y=-r,yy=y*y,sy=y0+y;y<=+r;y++,yy=y*y,sy++) if ((sy>=0)&&(sy<ys))
     for (x=-r,xx=x*x,sx=x0+x;x<=+r;x++,xx=x*x,sx++) if ((sx>=0)&&(sx<xs))
      if (xx+yy<=rr)          // inside circle
       if ((x*uy)-(y*ux)<=0)  // x,y is above a0 in clockwise direction
        if ((x*vy)-(y*vx)>=0) // x,y is below a1 in counter clockwise direction
         Pixels[sy][sx]=c; // change for putpixel
    }

Sin embargo, no uso BGI, así que simplemente cambie el Pixels[sy][sx]=c; con tu putpixel(sx,sy,c); y elimine los intervalos de verificación obsoletos para sx,sy. Quitar también la resolución. xs,ys y Pixels variables

Aquí vista previa para (xs2,ys2 es el mío en medio de la pantalla):

pie(xs2,ys2,ys2-200,10,50,0x00FF0000);

avance

Tenga en cuenta que tengo color RGB de 32 bits en lugar de los de 8 bits indexados y los ángulos están en grados. También tenga en cuenta que el eje y de la mina apunta hacia abajo, por lo que el ángulo de incremento va en el sentido de las agujas del reloj a partir del eje x (apuntando hacia la derecha)

Sin embargo, esto solo funciona para tartas por debajo de 180 grados. Para los más grandes, debe invertir las condiciones del producto cruzado para que se representen cuando no estén dentro de la parte del pastel no llena, en lugar de algo como esto:

void pie(int x0,int y0,int r,int a0,int a1,DWORD c) // a0 < a1
    {
    // variables
    int  x, y,      // circle centered point
        xx,yy,rr,   // x^2,y^2,r^2
        ux,uy,      // u
        vx,vy,      // v
        sx,sy;      // pixel position
    // my Pixel access
    int **Pixels=Main->pyx;         // Pixels[y][x]
    int   xs=Main->xs;              // resolution
    int   ys=Main->ys;
    // init variables
    rr=r*r;
    ux=double(r)*cos(double(a0)*M_PI/180.0);
    uy=double(r)*sin(double(a0)*M_PI/180.0);
    vx=double(r)*cos(double(a1)*M_PI/180.0);
    vy=double(r)*sin(double(a1)*M_PI/180.0);
    // handle big/small pies
    x=a1-a0;
    if (x<0) x=-x;
    // render small pies
    if (x<180)
        {
        for (y=-r,yy=y*y,sy=y0+y;y<=+r;y++,yy=y*y,sy++) if ((sy>=0)&&(sy<ys))
         for (x=-r,xx=x*x,sx=x0+x;x<=+r;x++,xx=x*x,sx++) if ((sx>=0)&&(sx<xs))
          if (xx+yy<=rr)           // inside circle
           if (((x*uy)-(y*ux)<=0)  // x,y is above a0 in clockwise direction
             &&((x*vy)-(y*vx)>=0)) // x,y is below a1 in counter clockwise direction
             Pixels[sy][sx]=c;
        }
    else{
        for (y=-r,yy=y*y,sy=y0+y;y<=+r;y++,yy=y*y,sy++) if ((sy>=0)&&(sy<ys))
         for (x=-r,xx=x*x,sx=x0+x;x<=+r;x++,xx=x*x,sx++) if ((sx>=0)&&(sx<xs))
          if (xx+yy<=rr)           // inside circle
           if (((x*uy)-(y*ux)<=0)  // x,y is above a0 in clockwise direction
             ||((x*vy)-(y*vx)>=0)) // x,y is below a1 in counter clockwise direction
             Pixels[sy][sx]=c;
        }
    }

vista previa de pastel grande

pie(xs2,ys2,ys2-200,50,340,0x00FF0000);

El código se puede optimizar aún más, por ejemplo x*uy se puede cambiar a la adición en el ciclo como for(...,xuy=x*uy;...;...,xuy+=uy) eliminando la multiplicación lenta de los bucles internos. Lo mismo ocurre con las 4 termias en las condiciones de productos cruzados.

[edit1] Para ser más claro tenemos algo como esto:

     for (x=-r,xx=x*x,sx=x0+x;x<=+r;x++,xx=x*x,sx++)
       {
       if (...(x*uy)...) { do something }
       }

la (x*uy) se calcula en cada iteración de x. Él x está aumentando, por lo que podemos calcular el valor de (x*uy) del valor anterior ((x-1)*uy)+uy que no necesita multiplicación como ((x-1)*uy) es el valor de la última iteración. Entonces, agregar una sola variable que lo contiene puede eliminar la multiplicación repetida:

     int xuy; //              ********                       *******
     for (x=-r,xx=x*x,sx=x0+x,xuy=x*uy;x<=+r;x++,xx=x*x,sx++,xuy+=uy)
       {
       if (...(xuy)...) { do something }
       }

entonces la multiplicación inicial se hace solo una vez y de ahí su suma…

Además, esta forma de renderizar es totalmente paralelizable…

  • No entendí la parte del bucle for, ¿puedes explicar eso?

    usuario10626935

    7 oct 2019 a las 15:24

  • por qué usaste rr=r*r?Yo creo r es el radio, entonces, ¿por qué dos radios diferentes para un círculo? También en x=a1-a0 donde estara a1 y a0 ¿viene de? Por último, tenemos if (x<180) entonces de que sirve if(x<0) x=-x. No entendí la referencia de píxel pequeño. Y eso si mas declaraciones tienen las mismas condiciones. ¿No debería ser diferente?

    usuario10626935

    9 de octubre de 2019 a las 7:46


  • @NetranjitBorgohain Todo es solo MATEMÁTICAS BÁSICAS: 1. Obtuve rr=r*r sí, es el mismo radio pero al cuadrado porque la ecuación del círculo lleno es x^2 + y^2 <= r^2 así que solo está precalculado r^2 así que no necesito cuadrarlo en cada píxel… 2. a0,a1 son los ángulos inicial y final de su pastel pasados ​​como operandos a la función. 3. la parte del código que estás preguntando x sobre retenciones x=abs(a1-a0) es por eso if (x<0) x=-x su valor abs justo. no tiene nada que ver con los píxeles que solo uso x como variable temporal porque aún no se usó. la x<180 determina si su pastel es más pequeño o más grande que 180 grados.

    – Espectro

    9 de octubre de 2019 a las 7:52


  • Gracias, me aclaró muchas dudas. Me pondré en contacto con usted, si encuentro más. Muchas gracias, me has ayudado en mis tiempos oscuros.

    usuario10626935

    9 de octubre de 2019 a las 8:07

  • ¿Por qué usaste ux,ux,vx,vy en lugar de solo u y v ?

    usuario10626935

    10 oct 2019 a las 19:41

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad