В данном приложении приведены процедуры, обеспечивающие выполнение отсечения по прямоугольному и многоугольному выпуклому окну и тестовая программа проверки работы процедур отсечения.
/*=================================================== V_CLIP.C * * Подрограммы, связанные с отсечением: * * V_SetPclip - установить размеры многоугольного окна * отсечения * V_SetRclip - установить размеры прямоугольного окна * отсечения * V_GetRclip - опросить размеры прямоугольного окна * отсечения * V_CSclip - отсечение по алгоритму Коэна-Сазерленда * прямоугольное окно, кодирование * концов отсекаемого отрезка * V_FCclip - отсечение по алгоритму быстрого отсечения * Алгоритм Собкова-Поспишила-Янга - * прямоугольное окно, кодирование * отсекаемого отрезка * V_LBclip - отсечение по алгоритму Лианга-Барски * прямоугольное окно, параметрическое * представление линий * V_CBclip - отсечение по алгоритму Кируса-Бека * окно - выпуклый многоугольник, * параметрическое представление линий */ /* Глобальные скаляры для алгоритмов отсечения по * прямоугольному окну - Коэна-Сазерленда, Fc-алгоритм, * Лианга-Барски */ static float Wxlef= 0.0, /* Координаты левого нижнего и */ Wybot= 0.0, /* правого верхнего углов окна */ Wxrig= 7.0, /* отсечения */ Wytop= 5.0; /* Глобальные скаляры для алгоритма Кируса-Бека * отсечения по многоугольному окну */ /* Координаты прямоугольного окна */ static float Wxrect[4]= {0.0, 0.0, 7.0, 7.0 }; static float Wyrect[4]= {0.0, 5.0, 5.0, 0.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;
/*------------------------------------------------- V_SetPclip * Устанавливает многоугольное окно отсечения * kv - количество вершин в окне * wx - X-координаты вершин * wy - Y-координаты вершин * nx - X-координаты нормалей к ребрам * ny - Y-координаты нормалей к ребрам * * Проверяет окно на выпуклость и невырожденность * * Если окно правильное, то * 1. Обновляет глобалы описания многоугольного окна: * Windn= kv; * Windx= wx; Windy= wy; --Координаты вершин окна * Wnormx= nx; Wnormy= ny; --Координаты перпендикуляров * * 2. Вычисляет координаты перепендикуляров к сторонам окна * * Возвращает: * 0 - норма * 1 - вершин менее трех * 2 - многоугольник вырожден в отрезок * 3 - многоугольник невыпуклый */ int V_SetPclip (kv, wx, wy, nx, ny) int kv; float *wx, *wy, *nx, *ny; { int ii, jj, sminus, splus, szero, otw; float r, vox, voy, /* Координаты (i-1)-й вершины */ vix, viy, /* Координаты i-й вершины */ vnx, vny; /* Координаты (i+1)-й вершины */ /* Проверка на выпуклость * для этого вычисляются векторные произведения * смежных сторон и определяется знак * если все знаки == 0 то многоугольник вырожден * если все знаки >= 0 то многоугольник выпуклый * если все знаки <= 0 то многоугольник невыпуклый */ otw= 0; if (--kv < 2) {++otw; goto all; } sminus= 0; splus= 0; szero= 0; vox= wx[kv]; voy= wy[kv]; vix= *wx; viy= *wy; ii= 0; do { if (++ii > kv) ii= 0; /* Следующая вершина */ vnx= wx[ii]; vny= wy[ii]; /* Координаты (i+1)-й */ r= (vix-vox)*(vny-viy) - /* Вект произв ребер */ (viy-voy)*(vnx-vix); /* смежных с i-й верш */ if (r < 0) ++sminus; else if (r > 0) ++splus; else ++szero; vox= vix; voy= viy; /* Обновлен координат */ vix= vnx; viy= vny; } while (ii); if (!splus && !sminus) /* Все векторные равны нулю */ {otw= 2; goto all; } /* Многоугольник вырожден */ if (splus && sminus) /* Знакопеременн. векторные */ {otw= 3; goto all; } /* Многоугольник невыпуклый */ /* Установление глобалов для правильного окна */ Windn= kv+1; /* Количество вершин у окна */ Windx= wx; Windy= wy; /* Координаты вершин окна */ Wnormx= nx; Wnormy= ny; /* Координ. перпендикуляров */ /* Вычисление координат перпендикуляров к сторонам */ vox= *wx; voy= *wy; ii= 0; do { if (++ii > kv) ii= 0; vix= wx[ii]; viy= wy[ii]; /* Текущая вершина */ vnx= viy-voy; vny= vox-vix; /* Поворот по часовой */ if (splus) { /* Внутр нормали влево */ vnx= -vnx; vny= -vny; } *nx++= vnx; *ny++= vny; vox= vix; voy= viy; /* Обновление координат */ } while (ii); all: return (otw); } /* V_SetPclip */
/*------------------------------------------------- V_SetRclip * Устанавливает прямоугольное окно отсечения * Возвращает 0/1 - нет/есть ошибки в задании окна */ int V_SetRclip (xleft, ybottom, xright, ytop) float xleft, ybottom, xright, ytop; { int otw; otw= 0; if (xleft >= xright || ybottom >= ytop) ++otw; else { Windn= 4; Windx= Wxrect; Windy= Wyrect; /* Вершины */ Wxlef= Wxrect[0]= Wxrect[1]= xleft; Wybot= Wyrect[0]= Wyrect[3]= ybottom; Wxrig= Wxrect[2]= Wxrect[3]= xright; Wytop= Wyrect[1]= Wyrect[2]= ytop; Wnormx= WxNrec; Wnormy= WyNrec; /* Нормали */ WxNrec[0]= 1; WyNrec[0]= 0; WxNrec[1]= 0; WyNrec[1]= -1; WxNrec[2]= -1; WyNrec[2]= 0; WxNrec[3]= 0; WyNrec[3]= 1; } return (otw); } /* V_SetRclip */
/*------------------------------------------------- V_GetRclip * Возвращает текущее прямоугольное окно отсечения */ void V_GetRclip (xleft, ybottom, xright, ytop) float *xleft, *ybottom, *xright, *ytop; { *xleft= Wxlef; *ybottom= Wybot; *xright= Wxrig; *ytop= Wytop; } /* V_GetRclip */
/*--------------------------------------------------- V_CSclip * Реализует алгоритм отсечения Коэна-Сазерленда с * кодированием концов отсекаемого отрезка * * int V_CSclip (float *x0, float *y0, float *x1, float *y1) * * Отсекает отрезок, заданный значениями координат его * точек (x0,y0), (x1,y1), по окну отсечения, заданному * глобальными скалярами Wxlef, Wybot, Wxrig, Wytop * * Конечным точкам отрезка приписываются коды, * характеризующие его положение относительно окна отсечения * по правилу: * * 1001 | 1000 | 1010 * -----|------|----- * | Окно | * 0001 | 0000 | 0010 * -----|------|----- * 0101 | 0100 | 0110 * * Отрезок целиком видим если оба его конца имеют коды 0000 * Если логическое И кодов концов не равно 0, то отрезок * целиком вне окна и он просто отбрасывается. * Если же результат этой операции = 0, то отрезок * подозрительный. Он может быть и вне и пересекать окно. * Для подозрительных отрезков определяются координаты их * пересечений с теми сторонами, с которыми они могли бы * пересечься в соответствии с кодами концов. * При этом используется горизонтальность и вертикальность * сторон окна, что позволяет определить одну из координат * без вычислений. * Часть отрезка, оставшаяся за окном отбрасывается. * Оставшаяся часть отрезка проверяется на возможность его * принятия или отбрасывания целиком. Если это невозможно, * то процесс повторяется для другой стороны окна. * На каждом цикле вычислений конечная точка отрезка, * выходившая за окно, заменяется на точку, лежащую или на * стороне окна или его продолжении. * * Вспомогательная процедура Code вычисляет код положения * для конца отрезка. * */
static float CSxn, CSyn; /* Координаты начала отрезка */ static int CScode (void) /* Определяет код точки xn, yn */ { register int i; i= 0; if (CSxn < Wxlef) ++i; else if (CSxn > Wxrig) i+= 2; if (CSyn < Wybot) i+= 4; else if (CSyn > Wytop) i+= 8; return (i); } /* CScode */
int V_CSclip (x0, y0, x1, y1) float *x0, *y0, *x1, *y1; { float CSxk, CSyk; /* Координаты конца отрезка */ int cn, ck, /* Коды концов отрезка */ visible, /* 0/1 - не видим/видим*/ ii, s; /* Рабочие переменные */ float dx, dy, /* Приращения координат*/ dxdy,dydx, /* Наклоны отрезка к сторонам */ r; /* Рабочая переменная */ CSxk= *x1; CSyk= *y1; CSxn= *x1; CSyn= *y1; ck= CScode (); CSxn= *x0; CSyn= *y0; cn= CScode (); /* Определение приращений координат и наклонов отрезка * к осям. Заодно сразу на построение передается отрезок, * состоящий из единственной точки, попавшей в окно */ dx= CSxk - CSxn; dy= CSyk - CSyn; if (dx != 0) dydx= dy / dx; else { if (dy == 0) { if (cn==0 && ck==0) goto out; else goto all; } } if (dy != 0) dxdy= dx / dy; /* Основной цикл отсечения */ visible= 0; ii= 4; do { if (cn & ck) break; /* Целиком вне окна */ if (cn == 0 && ck == 0) { /* Целиком внутри окна */ ++visible; break; } if (!cn) { /* Если Pn внутри окна, то */ s= cn; cn= ck; ck= s; /* перестить точки Pn,Pk и */ r=CSxn; CSxn=CSxk; CSxk=r; /* их коды, чтобы Pn */ r=CSyn; CSyn=CSyk; CSyk=r; /* оказалась вне окна */ } /* Теперь отрезок разделяется. Pn помещается в точку * пересечения отрезка со стороной окна. */ if (cn & 1) { /* Пересечение с левой стороной */ CSyn= CSyn + dydx * (Wxlef-CSxn); CSxn= Wxlef; } else if (cn & 2) { /* Пересечение с правой стороной*/ CSyn= CSyn + dydx * (Wxrig-CSxn); CSxn= Wxrig; } else if (cn & 4) { /* Пересечение в нижней стороной*/ CSxn= CSxn + dxdy * (Wybot-CSyn); CSyn= Wybot; } else if (cn & 8) { /*Пересечение с верхней стороной*/ CSxn= CSxn + dxdy * (Wytop-CSyn); CSyn= Wytop; } cn= CScode (); /* Перевычисление кода точки Pn */ } while (--ii >= 0); if (visible) { out: *x0= CSxn; *y0= CSyn; *x1= CSxk; *y1= CSyk; } all: return (visible); } /* V_CSclip */
/*--------------------------------------------------- V_FCclip * Реализует алгоритм отсечения FC (Fast Clipping) * Собкова-Поспишила-Янга, с кодированием линий * * int V_FCclip (float *x0, float *y0, float *x1, float *y1) * * Отсекает отрезок, заданный значениями координат его * точек (x0,y0), (x1,y1), по окну отсечения, заданному * глобальными скалярами Wxlef, Wybot, Wxrig, Wytop * * Возвращает: * -1 - ошибка в задании окна * 0 - отрезок не видим * 1 - отрезок видим */
static float FC_xn, FC_yn, FC_xk, FC_yk; static void Clip0_Top(void) {FC_xn= FC_xn + (FC_xk-FC_xn)*(Wytop-FC_yn)/(FC_yk-FC_yn); FC_yn= Wytop; } static void Clip0_Bottom(void) {FC_xn= FC_xn + (FC_xk-FC_xn)*(Wybot-FC_yn)/(FC_yk-FC_yn); FC_yn= Wybot; } static void Clip0_Right(void) {FC_yn= FC_yn + (FC_yk-FC_yn)*(Wxrig-FC_xn)/(FC_xk-FC_xn); FC_xn= Wxrig; } static void Clip0_Left(void) {FC_yn= FC_yn + (FC_yk-FC_yn)*(Wxlef-FC_xn)/(FC_xk-FC_xn); FC_xn= Wxlef; } static void Clip1_Top(void) {FC_xk= FC_xk + (FC_xn-FC_xk)*(Wytop-FC_yk)/(FC_yn-FC_yk); FC_yk= Wytop; } static void Clip1_Bottom(void) {FC_xk= FC_xk + (FC_xn-FC_xk)*(Wybot-FC_yk)/(FC_yn-FC_yk); FC_yk= Wybot; } static void Clip1_Right(void) {FC_yk= FC_yk + (FC_yn-FC_yk)*(Wxrig-FC_xk)/(FC_xn-FC_xk); FC_xk= Wxrig; } static void Clip1_Left(void) {FC_yk= FC_yk + (FC_yn-FC_yk)*(Wxlef-FC_xk)/(FC_xn-FC_xk); FC_xk= Wxlef; }
int V_FCclip (x0, y0, x1, y1) float *x0, *y0, *x1, *y1; { int Code= 0; int visible= 0; /* Отрезок невидим */ FC_xn= *x0; FC_yn= *y0; FC_xk= *x1; FC_yk= *y1; /* * Вычисление значения Code - кода отрезка * Биты 0-3 - для конечной точки, 4-7 - для начальной * */ if (FC_yk > Wytop) Code+= 8; else if (FC_yk < Wybot) Code+= 4; if (FC_xk > Wxrig) Code+= 2; else if (FC_xk < Wxlef) Code+= 1; if (FC_yn > Wytop) Code+= 128; else if (FC_yn < Wybot) Code+= 64; if (FC_xn > Wxrig) Code+= 32; else if (FC_xn < Wxlef) Code+= 16; /* Отсечение для каждого из 81-го случаев */ switch (Code) { /* Из центра */ case 0x00: ++visible; break; case 0x01: Clip1_Left() ; ++visible; break; case 0x02: Clip1_Right(); ++visible; break; case 0x04: Clip1_Bottom(); ++visible; break; case 0x05: Clip1_Left() ; if (FC_yk < Wybot) Clip1_Bottom(); ++visible; break; case 0x06: Clip1_Right(); if (FC_yk < Wybot) Clip1_Bottom(); ++visible; break; case 0x08: Clip1_Top(); ++visible; break; case 0x09: Clip1_Left() ; if (FC_yk > Wytop) Clip1_Top(); ++visible; break; case 0x0A: Clip1_Right(); if (FC_yk > Wytop) Clip1_Top(); ++visible; break;
/* Слева */ case 0x10: Clip0_Left(); ++visible; case 0x11: break; /* Отброшен */ case 0x12: Clip0_Left(); Clip1_Right(); ++visible; break; case 0x14: Clip0_Left(); if (FC_yn < Wybot) break; /* Отброшен */ Clip1_Bottom(); ++visible; case 0x15: break; /* Отброшен */ case 0x16: Clip0_Left(); if (FC_yn < Wybot) break; /* Отброшен */ Clip1_Bottom(); if (FC_xk > Wxrig) Clip1_Right(); ++visible; break; case 0x18: Clip0_Left(); if (FC_yn > Wytop) break; /* Отброшен */ Clip1_Top(); ++visible; case 0x19: break; /* Отброшен */ case 0x1A: Clip0_Left(); if (FC_yn > Wytop) break; /* Отброшен */ Clip1_Top(); if (FC_xk > Wxrig) Clip1_Right(); ++visible; break;
/* Справа */ case 0x20: Clip0_Right(); ++visible; break; case 0x21: Clip0_Right(); Clip1_Left(); ++visible; case 0x22: break; /* Отброшен */ case 0x24: Clip0_Right(); if (FC_yn < Wybot) break; /* Отброшен */ Clip1_Bottom(); ++visible; break; case 0x25: Clip0_Right(); if (FC_yn < Wybot) break; /* Отброшен */ Clip1_Bottom(); if (FC_xk < Wxlef) Clip1_Left(); ++visible; case 0x26: break; /* Отброшен */ case 0x28: Clip0_Right(); if (FC_yn > Wytop) break; /* Отброшен */ Clip1_Top(); ++visible; break; case 0x29: Clip0_Right(); if (FC_yn > Wytop) break; /* Отброшен */ Clip1_Top(); if (FC_xk < Wxlef) Clip1_Left(); ++visible; case 0x2A: break; /* Отброшен */
/* Снизу */ case 0x40: Clip0_Bottom(); ++visible; break; case 0x41: Clip0_Bottom(); if (FC_xn < Wxlef) break; /* Отброшен */ Clip1_Left() ; if (FC_yk < Wybot) Clip1_Bottom(); ++visible; break; case 0x42: Clip0_Bottom(); if (FC_xn > Wxrig) break; /* Отброшен */ Clip1_Right(); ++visible; case 0x44: case 0x45: case 0x46: break; /* Отброшен */ case 0x48: Clip0_Bottom(); Clip1_Top(); ++visible; break; case 0x49: Clip0_Bottom(); if (FC_xn < Wxlef) break; /* Отброшен */ Clip1_Left() ; if (FC_yk > Wytop) Clip1_Top(); ++visible; break; case 0x4A: Clip0_Bottom(); if (FC_xn > Wxrig) break; /* Отброшен */ Clip1_Right(); if (FC_yk > Wytop) Clip1_Top(); ++visible; break;
/* Снизу слева */ case 0x50: Clip0_Left(); if (FC_yn < Wybot) Clip0_Bottom(); ++visible; case 0x51: break; /* Отброшен */ case 0x52: Clip1_Right(); if (FC_yk < Wybot) break; /* Отброшен */ Clip0_Bottom(); if (FC_xn < Wxlef) Clip0_Left(); ++visible; case 0x54: case 0x55: case 0x56: break; /* Отброшен */ case 0x58: Clip1_Top(); if (FC_xk < Wxlef) break; /* Отброшен */ Clip0_Bottom(); if (FC_xn < Wxlef) Clip0_Left(); ++visible; case 0x59: break; /* Отброшен */ case 0x5A: Clip0_Left(); if (FC_yn > Wytop) break; /* Отброшен */ Clip1_Right(); if (FC_yk < Wybot) break; /* Отброшен */ if (FC_yn < Wybot) Clip0_Bottom(); if (FC_yk > Wytop) Clip1_Top(); ++visible; break;
/* Снизу-справа */ case 0x60: Clip0_Right(); if (FC_yn < Wybot) Clip0_Bottom(); ++visible; break; case 0x61: Clip1_Left() ; if (FC_yk < Wybot) break; /* Отброшен */ Clip0_Bottom(); if (FC_xn > Wxrig) Clip0_Right(); ++visible; case 0x62: case 0x64: case 0x65: case 0x66: break; /* Отброшен */ case 0x68: Clip1_Top(); if (FC_xk > Wxrig) break; /* Отброшен */ Clip0_Right(); if (FC_yn < Wybot) Clip0_Bottom(); ++visible; break; case 0x69: Clip1_Left() ; if (FC_yk < Wybot) break; /* Отброшен */ Clip0_Right(); if (FC_yn > Wytop) break; /* Отброшен */ if (FC_yk > Wytop) Clip1_Top(); if (FC_yn < Wybot) Clip0_Bottom(); ++visible; case 0x6A: break; /* Отброшен */
/* Сверху */ case 0x80: Clip0_Top(); ++visible; break; case 0x81: Clip0_Top(); if (FC_xn < Wxlef) break; /* Отброшен */ Clip1_Left() ; ++visible; break; case 0x82: Clip0_Top(); if (FC_xn > Wxrig) break; /* Отброшен */ Clip1_Right(); ++visible; break; case 0x84: Clip0_Top(); Clip1_Bottom(); ++visible; break; case 0x85: Clip0_Top(); if (FC_xn < Wxlef) break; /* Отброшен */ Clip1_Left() ; if (FC_yk < Wybot) Clip1_Bottom(); ++visible; break; case 0x86: Clip0_Top(); if (FC_xn > Wxrig) break; /* Отброшен */ Clip1_Right(); if (FC_yk < Wybot) Clip1_Bottom(); ++visible; case 0x88: case 0x89: case 0x8A: break; /* Отброшен */
/* Сверху-слева */ case 0x90: Clip0_Left(); if (FC_yn > Wytop) Clip0_Top(); ++visible; case 0x91: break; /* Отброшен */ case 0x92: Clip1_Right(); if (FC_yk > Wytop) break; /* Отброшен */ Clip0_Top(); if (FC_xn < Wxlef) Clip0_Left(); ++visible; break; case 0x94: Clip1_Bottom(); if (FC_xk < Wxlef) break; /* Отброшен */ Clip0_Left(); if (FC_yn > Wytop) Clip0_Top(); ++visible; case 0x95: break; /* Отброшен */ case 0x96: Clip0_Left(); if (FC_yn < Wybot) break; /* Отброшен */ Clip1_Right(); if (FC_yk > Wytop) break; /* Отброшен */ if (FC_yn > Wytop) Clip0_Top(); if (FC_yk < Wybot) Clip1_Bottom(); ++visible; case 0x98: case 0x99: case 0x9A: break; /* Отброшен */
/* Сверху-справа */ case 0xA0: Clip0_Right(); if (FC_yn > Wytop) Clip0_Top(); ++visible; break; case 0xA1: Clip1_Left() ; if (FC_yk > Wytop) break; /* Отброшен */ Clip0_Top(); if (FC_xn > Wxrig) Clip0_Right(); ++visible; case 0xA2: break; /* Отброшен */ case 0xA4: Clip1_Bottom(); if (FC_xk > Wxrig) break; /* Отброшен */ Clip0_Right(); if (FC_yn > Wytop) Clip0_Top(); ++visible; break; case 0xA5: Clip1_Left() ; if (FC_yk > Wytop) break; /* Отброшен */ Clip0_Right(); if (FC_yn < Wybot) break; /* Отброшен */ if (FC_yk < Wybot) Clip1_Bottom(); if (FC_yn > Wytop) Clip0_Top(); ++visible; case 0xA6: /* Отброшен */ case 0xA8: case 0xA9: case 0xAA: break;
/* Ошибка */ default: visible= -1; break; } /* switch */ if (visible > 0) { *x0= FC_xn; *y0= FC_yn; *x1= FC_xk; *y1= FC_yk; } return (visible); } /* V_FCclip */
/*--------------------------------------------------- V_LBclip * Реализует алгоритм отсечения Лианга-Барски * с параметрическим заданием линий * * int V_LBclip (float *x0, float *y0, float *x1, float *y1) * * Отсекает отрезок, заданный значениями координат его * точек (x0,y0), (x1,y1), по окну отсечения, заданному * глобальными скалярами Wxlef, Wybot, Wxrig, Wytop * * Возвращает: * 0 - отрезок не видим * 1 - отрезок видим */ static float LB_t0, LB_t1; static int LB_tclip (p, q) float p, q; { int accept; float r; accept= 1; /* Отрезок принят */ if (p == 0) { if (q < 0) accept= 0; /* Отбрасывание */ } else { r= q/p; if (p < 0) { if (r > LB_t1) accept= 0; /* Отбрасывание */ else if (r > LB_t0) LB_t0= r; } else { if (r < LB_t0) accept= 0; /* Отбрасывание */ else if (r < LB_t1) LB_t1= r; } } return (accept); } /* LB_tclip */
int V_LBclip (x0, y0, x1, y1) float *x0, *y0, *x1, *y1; { int visible; float dx, dy; visible= 0; LB_t0= 0; LB_t1= 1; dx= *x1 - *x0; if (LB_tclip (-dx, *x0-Wxlef)) { if (LB_tclip (dx, Wxrig-*x0)) { dy= *y1 - *y0; if (LB_tclip (-dy, *y0-Wybot)) { if (LB_tclip (dy, Wytop-*y0)) { if (LB_t1 < 1) { *x1= *x0 + LB_t1*dx; *y1= *y0 + LB_t1*dy; } if (LB_t0 > 0) { *x0= *x0 + LB_t0*dx; *y0= *y0 + LB_t0*dy; } ++visible; } } } } return (visible); } /* V_LBclip */
/*--------------------------------------------------- V_CBclip * Реализует алгоритм отсечения Кируса-Бека * по произвольному выпуклому многоугольнику * с параметрическим заданием линий * * int V_CBclip (float *x0, float *y0, float *x1, float *y1) * * Отсекает отрезок, заданный значениями координат его * точек (x0,y0), (x1,y1), по окну отсечения, заданному * глобальными скалярами: * int Windn - количество вершин в окне отсечения * float *Windx, *Windy - массивы X,Y координат вершин * float *Wnormx, *Wnormy - массивы координат нормалей * к ребрам * * Возвращает: * 0 - отрезок не видим * 1 - отрезок видим */
int V_CBclip (x0, y0, x1, y1) float *x0, *y0, *x1, *y1; { int ii, jj, visible, kw; float xn, yn, dx, dy, r; float CB_t0, CB_t1; /* Параметры концов отрезка */ float Qx, Qy; /* Положение относ ребра */ float Nx, Ny; /* Перпендикуляр к ребру */ float Pn, Qn; /**/ kw= Windn - 1; /* Ребер в окне */ visible= 1; CB_t0= 0; CB_t1= 1; dx= *x1 - (xn= *x0); dy= *y1 - (yn= *y0); for (ii=0; ii<=kw; ++ii) { /* Цикл по ребрам окна */ Qx= xn - Windx[ii]; /* Положения относ ребра */ Qy= yn - Windy[ii]; Nx= Wnormx[ii]; /* Перепендикуляр к ребру */ Ny= Wnormy[ii]; Pn= dx*Nx + dy*Ny; /* Скалярные произведения */ Qn= Qx*Nx + Qy*Ny; /* Анализ расположения */ if (Pn == 0) { /* Паралл ребру или точка */ if (Qn < 0) {visible= 0; break; } } else { r= -Qn/Pn; if (Pn < 0) { /* Поиск верхнего предела t */ if (r < CB_t0) {visible= 0; break; } if (r < CB_t1) CB_t1= r; } else { /* Поиск нижнего предела t */ if (r > CB_t1) {visible= 0; break; } if (r > CB_t0) CB_t0= r; } } } if (visible) { if (CB_t0 > CB_t1) visible= 0; else { if (CB_t0 > 0) { *x0= xn + CB_t0*dx; *y0= yn + CB_t0*dy; } if (CB_t1 < 1) { *x1= xn + CB_t1*dx; *y1= yn + CB_t1*dy; } } } return (visible); } /* V_CBclip */
/*=================================================== T_CLIP.C * * ТЕСТ ПРОЦЕДУР ОТСЕЧЕНИЯ */ #include <time.h> #include <stdio.h> /*--------------------------------------------------- V_DMclip * Пустышка для процедур отсечения */ int V_DMclip (x0, y0, x1, y1) float *x0, *y0, *x1, *y1; { int visible; visible= 1; return (visible); } /* V_DMclip */
/*---------------------------------------------------- ClipMsg * Печатает сообщение о результатах отсечения */ void ClipMsg (proc, visible, x0, y0, x1, y1, dt) char *proc; int visible; float x0, y0, x1, y1, dt; { if (visible < 0) { printf("*** ERROR (%s LineClip) - ", proc); printf("ошибка в координатах окна. "); printf("Прерывание с кодом ошибки 1."); exit (1); } else if (visible == 0) printf ("%s: Line is no visible dt=%f\n", proc, dt); else printf ("%s: ClipLine: x0=%f y0=%f x1=%f y1=%f dt=%f\n", proc, x0, y0, x1, y1, dt); } /* ClipMsg */
/*---------------------------------------------- MAIN T_CLIP.C */ void main (void) { float Wxn, Wyn, Wxk, Wyk; float Xn, Yn, Xk, Yk, x0, y0, x1, y1; int ii, numb= 1; float X_wind[100], Y_wind[100]; float X_norm[100], Y_norm[100]; int visible; float dt; time_t t1, t2; long ll, powt=10l; if (numb) goto set_win; m0:printf ("----Вершин= %d ? ", numb); scanf ("%d", &numb); for (ii=0; ii<numb; ++ii) { printf ("X_wind[%d], Y_wind[%d] ? ", ii, ii); scanf ("%f%f", &X_wind[ii], &Y_wind[ii]); } ii= V_SetPclip (numb, X_wind, Y_wind, X_norm, Y_norm); printf ("V_SetPclip= %d\n", ii); if (ii) goto m0; for (ii=0; ii<numb; ++ii) printf ("ind=%d X_norm=%f, Y_norm=%f\n", ii, X_norm[ii], Y_norm[ii]); if (ii) goto m0; /* Задание окна отсечения */ set_win: powt= 1l; V_GetRclip (&Wxn, &Wyn, &Wxk, &Wyk); for (;;) { printf ("Window: (Xn=%f Yn=%f Xk=%f Yk=%f) ? ", Wxn, Wyn, Wxk, Wyk); scanf ("%f%f%f%f", &Wxn, &Wyn, &Wxk, &Wyk); if (!V_SetRclip (Wxn, Wyn, Wxk, Wyk)) break; printf ("Error in a window boundarys\n"); } /* Ввод координат отрезка */ Xn= Wxn-1.0; Yn= Wyn-1.0; Xk= Wxk+1.0; Yk= Wyk+1.0; for (;;) { printf ("------------- "); printf ("ClipWindow: Xn=%f Yn=%f Xk=%f Yk=%f\n", Wxlef, Wybot, Wxrig, Wytop); printf ("New Line: (Xn=%f Yn=%f Xk=%f Yk=%f) ? ", Xn, Yn, Xk, Yk); scanf ("%f%f%f%f", &Xn, &Yn, &Xk, &Yk); ll= powt; t1= time(NULL); do { x0= Xn; y0= Yn; x1= Xk; y1= Yk; visible= V_DMclip (&x0, &y0, &x1, &y1); } while (--ll > 0l); t2= time (NULL); dt= ((float)(t2 - t1)); ClipMsg ("DM", visible, x0, y0, x1, y1, dt);
ll= powt; t1= time(NULL); do { x0= Xn; y0= Yn; x1= Xk; y1= Yk; visible= V_CSclip (&x0, &y0, &x1, &y1); } while (--ll > 0l); t2= time (NULL); dt= ((float)(t2 - t1)); ClipMsg ("CS", visible, x0, y0, x1, y1, dt); ll= powt; t1= time(NULL); do { x0= Xn; y0= Yn; x1= Xk; y1= Yk; visible= V_FCclip (&x0, &y0, &x1, &y1); } while (--ll > 0l); t2= time (NULL); dt= ((float)(t2 - t1)); ClipMsg ("FC", visible, x0, y0, x1, y1, dt); ll= powt; t1= time(NULL); do { x0= Xn; y0= Yn; x1= Xk; y1= Yk; visible= V_LBclip (&x0, &y0, &x1, &y1); } while (--ll > 0l); t2= time (NULL); dt= ((float)(t2 - t1)); ClipMsg ("LB", visible, x0, y0, x1, y1, dt); ll= powt; t1= time(NULL); do { x0= Xn; y0= Yn; x1= Xk; y1= Yk; visible= V_CBclip (&x0, &y0, &x1, &y1); } while (--ll > 0l); t2= time (NULL); dt= ((float)(t2 - t1)); ClipMsg ("CB", visible, x0, y0, x1, y1, dt); } }