Изобразить на экране поверхность, заданную уравнением z=f(x,y) в виде сетки координатных линий x=const, y=const. Использовать алгоритм плавающего горизонта для удаления невидимых линий. Обычно используют параллельное проектирование, при котором вертикальные линии (параллельные оси z в объектном пространстве) переходят в вертикальные линии на экране. Это достигается с помощью матрицы поворота : cos(phi) sin(phi)sin(psi) 0 0 sin(phi) -cos(phi)sin(psi) 0 0 0 cos(psi) 0 0 0 0 0 1 Основные идеи метода плавающего горизонта можно сформулировать следующим образом: Трехмерная задача сводится к двумерной путем пересечения исходной поверхности, последовательностью параллельных секущих плоскостей, имеющих постоянные значения координат выбранной одной (y) или двух (x и y) координатных осей. При этом углы phi и psi, определяющие ракурс, подбираются таким образом, что создаются вполне определенные "отношения экранирования" между линиями поверхности из одного семейства. Это означает, например для семейства y=const, что при yi В терминах координат (X,Y) картинной плоскости алгоритм имеет вид: Рассматриваем линии в порядке удаления. Если на текущей кривой при некотором заданном значении X соответствующее значение Y больше максимума или меньше минимума по Y для всех предыдущих кривых при этом X, то текущая кривая видима. В противном случае она невидима. Линии максимума и минимума играют роли плавающих верхнего и нижнего горизонтов. Пусть проекцией линии z = f(X, Yk) на картинную плоскость является линия Y = Yk(X) , где (X,Y) - координаты на картинной плоскости, причем Y соответствует вертикальной координате. Каждая из линий представляется в виде ломаной. Для рисования сегментов этой ломаной используется модифицированный алгоритм Брезенхейма, которой перед выводом очередного пикселя сравнивает его ординату с верхней и нижней контурными линиями, представляющими из себя в этом случае массивы значений ординат. #include<conio.h> #include<graphics.h> #include<math.h> #include<process.h> #include<stdio.h> #include<stdlib.h> #include<dos.h> #define NO_VALUE -777 #define MAXX 640 #define MAXY 480 int YMax[MAXX]; int YMin[MAXX]; int Psi, Phi, Dx, Dy; struct Point { int x; int y; }; int UpColor = 9; int DownColor = 15; double f(double x, double y) //функция конуса { double r = x*x/225 + y*y/64; return sqrt(r); } void DrawLine (Point &p1, Point &p2) {/*рисует сегменты ломаной, используя модифицированный алгоритм Брезенхейма*/ int dx = abs (p2.x - p1.x); int dy = abs (p2.y - p1.y); int sx = p2.x >= p1.x ? 1 : -1; int sy = p2.y >= p1.y ? 1 : -1; if (dy <= dx){ int d = -dx; int d1 = dy << 1; int d2 = (dy - dx) << 1; for (int x=p1.x, y=p1.y, i=0; i<=dx; i++, x+=sx) { if (YMin[x] == NO_VALUE){ putpixel(x,y,UpColor); YMin[x] = YMax[x] = y; } else if (y < YMin[x]){ putpixel(x,y,UpColor); YMin[x] = y; } else if (y > YMax[x]){ putpixel(x,y,DownColor); YMax[x] = y; } if (d > 0){ d += d2; y += sy; } else d += d1; } } else { int d = -dy; int d1 = dx << 1; int d2 = ( dx - dy ) << 1; int m1 = YMin[p1.x]; int m2 = YMax[p1.x]; for (int x=p1.x, y=p1.y, i=0; i<=dy; i++, y+=sy) { if (YMin[x] == NO_VALUE) { putpixel(x,y,UpColor); YMin[x] = YMax[x] = y; } else if (y < m1){ putpixel(x,y,UpColor); if (y < YMin[x]) YMin[x] = y; } else if (y > m2){ putpixel(x,y,DownColor); if (y > YMax[x]) YMax[x] = y; } if (d > 0){ d+=d2; x+=sx; m1 = YMin[x]; m2 = YMax [x]; } else d+=d1; } } } void PlotSurface( double x1, double y1, double x2, double y2, double fmin, double fmax, int n1, int n2)/*n1 - количество точек по Х, которые делят линию на сегменты; n2 - количество линий*/ { Point *CurLine = new Point [n1]; double phi = Phi*3.1415926/180; double psi = Psi*3.1415926/180; double sphi = sin(phi); double spsi = sin(psi); double cphi = cos(phi); double cpsi = cos(psi); double e1 [] = { cphi, sphi, 0 }; double e2 [] = { spsi * sphi, -spsi * cphi, cpsi }; double x,y; double hx = (x2 - x1)/n1; double hy = (y2 - y1)/n2; double xmin = (e1[0] >= 0 ? x1 : x2)*e1[0] + (e1[1] >= 0 ? y1 : y2)*e1[1]; double xmax = (e1[0] >= 0 ? x2 : x1)*e1[0] + (e1[1] >= 0 ? y2 : y1)*e1[1]; double ymin = (e2[0] >= 0 ? x1 : x2)*e2[0] + (e2[1] >= 0 ? y1 : y2)*e2[1]; double ymax = (e2[0] >= 0 ? x2 : x1)*e2[0] + (e2[1] >= 0 ? y2 : y1)*e2[1]; int i, j, k; if ( e2[2] >= 0 ){ ymin += fmin*e2[2]; ymax += fmax*e2[2]; } else { ymin += fmax*e2[2]; ymax += fmin*e2[2]; } double ax = Dx-(MAXX - 40)*xmin/(xmax - xmin); double bx = (MAXX - 40)/(xmax - xmin); double ay = Dy-(MAXY - 80)*ymin/(ymax - ymin); double by = -(MAXY - 80)/(ymax - ymin); for ( i=0; i<sizeof(YMax)/sizeof(int); i++) YMin[i] = YMax[i] = NO_VALUE; for ( i=n2-1; i>-1; i--){ for (j=0; j<n1; j++){ x = x1 + j*hx; y = y1 + i*hy; CurLine[j].x = (int)(ax + bx*(x*e1[0] + y*e1[1])); CurLine[j].y = (int)(ay + by*(x*e2[0] + y*e2[1] + f(x,y) * e2[2])); } for (j=0; j<n1-1; j++) DrawLine(CurLine[j], CurLine[j+1]); } delete []CurLine; } int main() { int dr = DETECT, md; int res; initgraph ( &dr, &md, ""); Psi = 3; Phi = 320; //угол поворота Dx = 20; //расположение по x Dy = 180; //по y PlotSurface(-5,-5,5,5,-0.2,0.3,1000,100 ); getch(); closegraph(); return 0; }
Ключевые слова:
алгоритм плавающего горизонта, удаление невидимых линий, уравнение конуса
|
|||