к оглавлению

Основные алгоритмы компьютерной графики

Процедуры отсечения многоугольника

    0.19.1  V_Plclip - простой алгоритм отсечения многоугольника
    0.19.2  Тест процедуры V_Plclip

В данном приложении содержатся процедуры V_Plclip, реализующие простой алгоритм отсечения произвольного многоугольника по выпуклому многоугольному окну отсечения и тестовая программа проверки их работы.

Процедуры реализуют алгоритм, который, как и алгоритм Сазерленда-Ходгмана, последовательно отсекает весь многоугольник по каждому из ребер окна отсечения.

0.19.1  V_Plclip - простой алгоритм отсечения многоугольника

/*=================================================== V_PLCLIP
 * Файл V_PLCLIP.C - процедуры простого алгоритма отсечния
 *                   многоугольника
 * Последняя редакция:
 * 25.12.93  17:25
 */

#include <graphics.h>
#include "V_WINDOW.C"   /* Глобалы и проц работы с окнами */

/* Включаемый файл V_WINDOW.C содержит
 * подрограммы и глобалы для окон:
 *
 * V_SetPclip - установить размеры многоугольного окна
 *              отсечения
 * V_GetPclip - опросить параметры многоугольного окна
 *              отсечения
 * V_SetRclip - установить размеры прямоугольного окна
 *              отсечения
 * V_GetRclip - опросить   размеры прямоугольного окна
 *              отсечения
 *
 * Глобальные скаляры для алгоритмов отсечения по
 * прямоугольному окну - Коэна-Сазерленда, Fc-алгоритм,
 * Лианга-Барски
 *
 * static float Wxlef= 100.0, -- Координаты левого нижнего и
 *              Wybot= 100.0, -- правого верхнего углов окна
 *              Wxrig= 300.0, -- отсечения
 *              Wytop= 200.0;
 *
 * Глобальные скаляры для алгоритма Кируса-Бека
 * отсечения по многоугольному окну
 *
 * Координаты прямоугольного окна
 * static float Wxrect[4]= {100.0, 100.0, 300.0, 300.0 };
 * static float Wyrect[4]= {100.0, 200.0, 200.0, 100.0 };
 *
 * Перепендикуляры к сторонам прямоугольного окна
 * static float WxNrec[4]= {1.0,  0.0, -1.0, 0.0 };
 * static float WyNrec[4]= {0.0, -1.0,  0.0, 1.0 };
 *
 * Данные для многоугольного окна
 * static int   Windn=4;          -- Кол-во вершин у окна
 * static float *Windx=  Wxrect,  -- Координаты вершин окна
 *              *Windy=  Wyrect;
 * static float *Wnormx= WxNrec,  -- Координаты нормалей
 *              *Wnormy= WyNrec;
 */


/*-------------------------------------------------- Pl_clip0
 * Служебная процедура, отсекает многоугольник
 * относительно одного ребра окна
 *
 * Отсечение выполняется в цикле по сторонам многоугольника
 * При первом входе в цикл только вычисляются величины для
 * начальной точки: координаты, скалярное произведение,
 * определяющее ее расположение относительно ребра окна, и
 * код расположения.
 * При последующих входах в цикл эти значения вычисляются
 * для очередной вершины.
 * По значениям кодов расположения вершин для стороны
 * многоугольника определяется как она расположена
 * относительно ребра и вычисляются координаты результирующего
 * многоугольника.
 */

static int Pl_clip0 (N_reb, N_in, X_in, Y_in, X_ou, Y_ou)
int   N_reb, N_in;
float *X_in, *Y_in, *X_ou, *Y_ou;
{
   int  ii, jj;
   int  pozb,      /* Коды расположения начальной точки  */
        pozn,      /* многоугольника и точек тек стороны */
        pozk;      /* 0/1/2 - пред точка вне/на/внутри   */
   float Rx,Ry;    /* Координаты начала ребра окна */
   float Nx, Ny;   /* Нормаль к  ребру окна */
   float xb, yb;   /* Начальная точка многоугольника  */
   float xn, yn;   /* Начальная точка текущей стороны */
   float xk, yk;   /* Конечная  точка текущей стороны */
   float t;        /* Значение параметра точки пересечения */
   float Qb,Qn,Qk; /* Скалярные произведения */
   float *ptx_ou;

/* Запрос параметров ребра окна */
   Rx= Windx[N_reb];  Ry= Windy[N_reb];
   Nx= Wnormx[N_reb]; Ny= Wnormy[N_reb];

/* Цикл отсчения многоугольника ребром окна */
   ii= 0;  ++N_in;  ptx_ou= X_ou;
   while (--N_in >= 0) {
      if (N_in) {
         xk= *X_in++;  yk= *Y_in++;   /* Кон точка стороны  */
         Qk= (xk-Rx)*Nx + (yk-Ry)*Ny; /* Параметр положения */
         pozk= 1;                     /* 1 - точка на гр. */
         if (Qk < 0) --pozk; else     /* 0 - точка вне    */
         if (Qk > 0) ++pozk;          /* 2 - точка внутри */
      } else {
         xk= xb;  yk= yb;  Qk= Qb;  pozk= pozb;
      }
      if (!ii) {
         xb= xn= xk; yb= yn= yk; Qb= Qn= Qk; pozb= pozn= pozk;
         ++ii; continue;
      }
      jj= 0;
      switch (pozn*3 + pozk) {     /* Стар Нов Выход     */
         case 0: goto no_point;    /*  вне-вне нет       */
         case 1: goto endpoint;    /*  вне-на  конечная  */
         case 2: goto intersec;    /*  вне-вну перес,кон */
         case 3: goto no_point;    /*  на -вне нет       */
         case 4:                   /*  на -на  конечная  */
         case 5: goto endpoint;    /*  на -вну конечная  */
         case 6: goto no_end;      /*  вну-вне пересечен */
         case 7:                   /*  вну-на  конечная  */
         case 8: goto endpoint;    /*  вну-вну конечная  */
      }
no_end: ++jj;
intersec:
      t= Qn/(Qn-Qk);
      *X_ou++= xn + t*(xk-xn);
      *Y_ou++= yn + t*(yk-yn);
      if (!jj) {
endpoint:
         *X_ou++= xk;  *Y_ou++= yk;
      }
no_point:
      xn= xk;  yn= yk;  Qn= Qk;  pozn= pozk;
   }
   return (X_ou - ptx_ou);
}  /* Pl_clip0 */


/*--------------------------------------------------- V_Plclip
 * Простая процедура отсечения многоугольника
 * N_in       - число вершин во входном многоугольнике
 * X_in, Y_in - координаты вершин отсекаемого мног-ка
 *              этот массив будет испорчен
 * Возвращает:
 *  < 0 - ошибки
 * >= 0 - количество вершин в выходном многоугольнике
 * X_ou, Y_ou - координаты вершин отсеченного многоугольника
 */

int  V_Plclip (N_in, X_in, Y_in, X_ou, Y_ou)
int   N_in;
float *X_in, *Y_in, *X_ou, *Y_ou;
{
   int  ii, N_ou; float *ptr;

   if ((N_ou= N_in) < 3) {N_ou= -1;  goto all; }
   if (Windn < 3) {N_ou= -2;  goto all; }
   for (ii=0; ii<Windn; ++ii) {
      N_ou= Pl_clip0 (ii, N_ou, X_in, Y_in, X_ou, Y_ou);
      ptr= X_in;  X_in= X_ou;  X_ou= ptr;
      ptr= Y_in;  Y_in= Y_ou;  Y_ou= ptr;
   }
   if (!(Windn & 1)) {
      ii= N_ou;
      while (--ii >= 0) {*X_ou++= *X_in++; *Y_ou++= *Y_in++; }
   }
all:
   return N_ou;
}  /* V_Plclip */


0.19.2  Тест процедуры V_Plclip

/*=================================================== T_PLCLIP
 * ТЕСТ процедуры V_Plclip для отсечения многоугольника
 *
 * При первом входе устанавливается восьмиугольное окно
 * отсечения:
 * X: 150, 100, 100, 150, 250, 300, 300, 250
 * Y: 100, 150, 250, 300, 300, 250, 150, 100
 *
 * И на нем отсекается треугольник:
 * (10,160),(90,220),(170,160)
 *
 * Затем выдается запрос на количество вершин в
 * новом отсекаемом многоугольнике:
 * --- Vertexs in polyline= XX ?
 * При вводе числа > 0 будут запрашиваться координаты вершин
 *                     много-ка и выполняться его отсечение
 * При вводе числа = 0 программа затребует ввод координат
 *                     нового прямоугольного окна отсечения
 * При вводе числа < 0 программа запросит переустановку
 *                     многоугольного окна отсечения:
 *
 * ----Vertexs in clip window= XX ?
 * При вводе числа > 0 будут запрашиваться координаты вершин.
 * При вводе числа = 0 программа затребует ввод координат
 *                     прямоугольного окна.
 * При вводе числа < 0 программа закончится.
 */


#include <graphics.h>
#include "V_PLCLIP.C"

/*--------------------------------------------------- DrawPoly
 * Чертит контур многоугольника
 */
void DrawPoly (col, n, x, y)
int col, n; float *x, *y;
{  int  ii, jj;
   setcolor (col);
   for (ii=0; ii<n; ++ii) {
      if ((jj= ii+1) >= n) jj= 0;
      line (x[ii], y[ii], x[jj], y[jj]);
   }
}  /* DrawPoly */

/*---------------------------------------------------- CLR_STR
 * Зачищает строку выводом в нее пробелов
 */
void CLR_STR (void)
{
printf ("                                                \r");
}

/*------------------------------------------------ PLCLIP_MAIN
 */
void main (void)
{  int   ii, jj,
         fon;           /* Индекс фона  */
   float Wxn,Wyn,       /* Прямоугольный отсекатель */
         Wxk,Wyk;
   int   N_wind= 0;     /* Вводимый отсекатель */
   float X_wind[100],
         Y_wind[100];
   float X_norm[100],
         Y_norm[100];
   int   wnum;          /* Запрошенный отсекатель */
   float *wx,*wy,*wnx,*wny;
   int   N_poly= 0;     /* Отсекаемый многугольник */
   float X_poly[100],
         Y_poly[100];
   int   N_clip= 0;     /* Отсеченный многугольник */
   float X_clip[100],
         Y_clip[100];
   int   entry= 0;      /* 0/1 - нет/был вывод по умолчанию */
   int   gdriver= DETECT, gmode;

   initgraph (&gdriver, &gmode, "");
   fon= 0;                      /* Цвет фона */

   setbkcolor(fon);             /* Очистка экрана */
   cleardevice();

/*--------------- Установить окно отсечения ----------------*/
new_window:
   gotoxy (1,1);
   if (!entry) {
      N_wind= 8;  wx= X_wind;  wy= Y_wind;
      *wx++= 150; *wx++= 100;  *wx++= 100; *wx++= 150;
      *wy++= 100; *wy++= 150;  *wy++= 250; *wy++= 300;

      *wx++= 250; *wx++= 300;  *wx++= 300; *wx++= 250;
      *wy++= 300; *wy++= 250;  *wy++= 150; *wy++= 100;
      goto wr_window;
   }
   if (!N_poly) goto set_rect;


/*---------- Задание многоугольного окна отсечения ---------*/
set_window:
   CLR_STR ();
   printf ("----Vertexs in clip window= %d ? ", N_wind);
   scanf  ("%d", &N_wind);
   if (N_wind < 0) goto all;
   if (!N_wind) goto set_rect;
   for (ii=0; ii<N_wind; ++ii) {
      CLR_STR ();
      printf ("X_wind[%d], Y_wind[%d] ? ", ii, ii);
      scanf  ("%f%f", &X_wind[ii], &Y_wind[ii]);
   }
wr_window:
   jj= V_SetPclip (N_wind, X_wind, Y_wind, X_norm, Y_norm);
   if (jj) {
      printf ("Error=%d in polyline window\n", jj);
      goto set_window;
   } else goto ou_win;


/*---------- Задание прямоугольного окна отсечения ---------*/
set_rect:
   V_GetRclip (&Wxn, &Wyn, &Wxk, &Wyk);
get_rect:
   CLR_STR ();
   printf ("Rect window: (Xn=%f Yn=%f Xk=%f Yk=%f) ? ",
            Wxn, Wyn, Wxk, Wyk);
   scanf  ("%f%f%f%f", &Wxn, &Wyn, &Wxk, &Wyk);
wr_rect:
   jj= V_SetRclip (Wxn, Wyn, Wxk, Wyk);
   if (jj) {
      printf ("Error=%d in rectangle window\n", jj);
      goto get_rect;
   }


/*--------------- Прорисовка окна отсечения ----------------*/
ou_win:
   wnum= V_GetPclip (&wx, &wy, &wnx, &wny);
   DrawPoly (LIGHTRED, wnum, wx, wy);


/*------- Ввод координат отсекаемого многоугольника --------*/

set_poly:
   gotoxy (1,1);
   if (!entry) { /* При первом входе отрисовка по умолчанию */
      N_poly= 3;
      X_poly[0]=  10;  X_poly[1]=  90;  X_poly[2]= 170;
      Y_poly[0]= 160;  Y_poly[1]= 220;  Y_poly[2]= 160;
   } else {
      CLR_STR ();
      printf ("--- Vertexs in polyline= %d ? ",N_poly);
      scanf  ("%d", &N_poly);
      if (N_poly <= 0) goto new_window;
      for (ii=0; ii<N_poly; ++ii) {
         printf ("                                   \r");
         printf ("X_poly[%d], Y_poly[%d] ? ", ii, ii);
         scanf  ("%f%f", &X_poly[ii], &Y_poly[ii]);
      }
   }
   ++entry;

/*---------- Прорисовка отсекателя и отсекаемого -----------*/
   wnum= V_GetPclip (&wx, &wy, &wnx, &wny);
   DrawPoly (LIGHTRED, wnum, wx, wy);
   DrawPoly (LIGHTGREEN, N_poly, X_poly, Y_poly);


/*----------------------- Отсечение ------------------------*/
   N_clip= V_Plclip(N_poly, X_poly, Y_poly, X_clip, Y_clip);

/*----------------- Прорисовка отсеченного -----------------*/
   DrawPoly (YELLOW, N_clip, X_clip, Y_clip);
   goto set_poly;

all:
   closegraph();
}  /* PLCLIP_MAIN */

1 Переход к модели с перечислением занятых точек также возможен из любой другой, но при решении проблем точности аппроксимации.

к оглавлению

Знаете ли Вы, как разрешается парадокс Ольберса?
(Фотометрический парадокс, парадокс Ольберса - это один из парадоксов космологии, заключающийся в том, что во Вселенной, равномерно заполненной звёздами, яркость неба (в том числе ночного) должна быть примерно равна яркости солнечного диска. Это должно иметь место потому, что по любому направлению неба луч зрения рано или поздно упрется в поверхность звезды.
Иными словами парадос Ольберса заключается в том, что если Вселенная бесконечна, то черного неба мы не увидим, так как излучение дальних звезд будет суммироваться с излучением ближних, и небо должно иметь среднюю температуру фотосфер звезд. При поглощении света межзвездным веществом, оно будет разогреваться до температуры звездных фотосфер и излучать также ярко, как звезды. Однако в дело вступает явление "усталости света", открытое Эдвином Хабблом, который показал, что чем дальше от нас расположена галактика, тем больше становится красным свет ее излучения, то есть фотоны как бы "устают", отдают свою энергию межзвездной среде. На очень больших расстояниях галактики видны только в радиодиапазоне, так как их свет вовсе потерял энергию идя через бескрайние просторы Вселенной. Подробнее читайте в FAQ по эфирной физике.

НОВОСТИ ФОРУМА

Форум Рыцари теории эфира


Рыцари теории эфира
 10.11.2021 - 12:37: ПЕРСОНАЛИИ - Personalias -> WHO IS WHO - КТО ЕСТЬ КТО - Карим_Хайдаров.
10.11.2021 - 12:36: СОВЕСТЬ - Conscience -> РАСЧЕЛОВЕЧИВАНИЕ ЧЕЛОВЕКА. КОМУ ЭТО НАДО? - Карим_Хайдаров.
10.11.2021 - 12:36: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от д.м.н. Александра Алексеевича Редько - Карим_Хайдаров.
10.11.2021 - 12:35: ЭКОЛОГИЯ - Ecology -> Биологическая безопасность населения - Карим_Хайдаров.
10.11.2021 - 12:34: ВОЙНА, ПОЛИТИКА И НАУКА - War, Politics and Science -> Проблема государственного терроризма - Карим_Хайдаров.
10.11.2021 - 12:34: ВОЙНА, ПОЛИТИКА И НАУКА - War, Politics and Science -> ПРАВОСУДИЯ.НЕТ - Карим_Хайдаров.
10.11.2021 - 12:34: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Вадима Глогера, США - Карим_Хайдаров.
10.11.2021 - 09:18: НОВЫЕ ТЕХНОЛОГИИ - New Technologies -> Волновая генетика Петра Гаряева, 5G-контроль и управление - Карим_Хайдаров.
10.11.2021 - 09:18: ЭКОЛОГИЯ - Ecology -> ЭКОЛОГИЯ ДЛЯ ВСЕХ - Карим_Хайдаров.
10.11.2021 - 09:16: ЭКОЛОГИЯ - Ecology -> ПРОБЛЕМЫ МЕДИЦИНЫ - Карим_Хайдаров.
10.11.2021 - 09:15: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Екатерины Коваленко - Карим_Хайдаров.
10.11.2021 - 09:13: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Вильгельма Варкентина - Карим_Хайдаров.
Bourabai Research - Технологии XXI века Bourabai Research Institution