Создайте "pieslice" в C без использования pieslice () из graphics.h - PullRequest
2 голосов
/ 03 октября 2019

В заголовочном файле библиотеки BGI "graphics.h" есть функция pieslice в этом заголовочном файле, ее синтаксис:

#include <graphics.h>

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

[x, y являются центромокружность, прямоугольник и конечный угол - соответственно начальный и конечный углы]

Можем ли мы сделать pieslice в C / C ++ без использования этой встроенной функции библиотеки BGI. Пожалуйста, помогите. Попытка сделать это с помощью линий и алгоритмов генерации окружности средней точки.

Мой код до сих пор:

#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();
}

Я смог выполнить часть вычисления, где я использовал параметрическийуравнение окружности, но не может сгенерировать фигуру с помощью функции graphics.h. Некоторая помощь была бы хороша. Заранее спасибо.

При запуске этой программы я получаю эту ошибку:

[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)


1 Ответ

2 голосов
/ 05 октября 2019

почему бы не использовать векторы?

pie

outscribed square

Итак (0,0) центрированный пироградиуса r определяется следующим образом:

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

CW / CCW определяется путем вычисления трехмерного перекрестного произведения и изучения результата результатов с координатой z ...

, поэтому обрабатывают все пикселипо кругу вписал квадрат и рендерил все пиксели, соответствующие всем 3 условиям.

Примерно так:

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
    }

Однако я не использую BGI, поэтому просто замените Pixels[sy][sx]=c; на putpixel(sx,sy,c); и удалите устаревшие проверки диапазона для sx,sy. Также удалите переменные разрешения xs,ys и Pixels.

Здесь предварительный просмотр для (xs2,ys2 - моя середина экрана):

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

preview

Обратите внимание, что у меня 32-битный цвет RGB вместо ваших индексированных 8-битных, а углы указаны в градусах. Также обратите внимание, что моя ось y направлена ​​вниз, так что угол приращения идет по часовой стрелке, начиная с оси x (указывая вправо)

Однако это работает только для пирогов ниже 180 градусов. Для больших вынеобходимо инвертировать условия перекрестного произведения для рендеринга, когда он не находится внутри незаполненной части пирога, вместо этого что-то вроде этого:

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

preview big pie

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

код можно дополнительно оптимизировать, например, x*uy можно изменить на сложение для цикла, например for(...,xuy=x*uy;...;...,xuy+=uy), устраняя медленное умножение из внутренних циклов. То же самое относится ко всем 4 термам в условиях перекрестного произведения.

[edit1] Для большей ясности мы имеем что-то вроде этого:

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

the (x*uy) вычисляется на каждой итерации x. x увеличивается, поэтому мы можем вычислить значение (x*uy) из предыдущего значения ((x-1)*uy)+uy, которое не нуждается в умножении, поскольку ((x-1)*uy) - это значение из последней итерации. Таким образом, добавление единственной переменной, которая содержит ее, может избавить от повторного умножения:

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

, поэтому начальное умножение выполняется только один раз, а затем просто его сложение ...

И такрендеринга полностью распараллеливается ...

...