Програмирование изображения поверхности z=f(x,y) с удалением невидимых линий используя алгоритм плавающего горизонта


Добавил:DMT
Дата создания:18 июня 2008, 23:54
Дата обновления:18 июня 2008, 23:54
Просмотров:12069 последний 25 марта, 17:09
Комментариев: 0
Вывести на экран изображение поверхности z=f(x,y) с удалением невидимых линий. Програмирование на Си/С, исходник
Удаление невидимых линий осуществляется с использованием алгоритма плавающего горизонта. Рассматривается центральная проекция. Поверхность задается формулой: z=x sin(y) -y sin(x)

Точки (x,y,z) вычерчиваемой части поверхности принадлежат некоторому прямоугольному параллелепипеду x min  <= x <= x max , y min  <= y <= y max , z min  <= z <= z max . Точка наблюдения (x V  ,y V  ,z V ) удовлетворяет условиям x V   ?  x max , y V  ?  y max , z V  ?  z max . Функции ex и ey переводят мировые координаты (x,y,z) в координаты проекции (x ? ,y ? ) . Плоскость проекции имеет единичный вектор нормали u = (cos a , sin a , 0) и находится на расстоянии d от точки (x V , y V  ,z V ) (см. рассмотренный ранее пример 3.3 на центральную проекцию). Координаты центральной проекции вычисляются по формулам:

x '=- d (( x - x V )(- sin a )+( y - y V ) cos a )/(( x - x V ) cos a +( y - y V ) sin a ) ;

y'=-d(z-z V )/((x-x V )cos a +(y-y V )sin a ) .

 

Вычислим наибольшие и наименьшие координаты отображаемого параллелепипеда

ex min  = ex(x max  ,y min  ,z min ), ex max  = ex(x min , y max , z max ),

ey min  = ey(x max , y max , z min ), ey max  = ey(x min , y min , z max ).

Прямоугольник ex min  <= ex <= ex max , ey min  <= ey <= ey max будет окном, отображаемым на область вывода, состоящую из точек, имеющих целые координаты

X = (ex-exmin)*getmaxx()/(exmax-exmin),Y = (ey-eymin)*getmaxy()/(eymax-eymin).

Рассматривается прямоугольная сетка в плоскости Oxy с шагом hx = (xmax-xmin)/nx по x , и hy = (ymax -ymin )/ny - по y .

Каждому прямоугольнику (( x j , y i ), ( x j , y i +1 ), ( x j +1 , y i +1 ), ( x j +1 , y i )), 0 <= j <= nx -1, 0 <= j <= n - y -1 на плоскости Oxy соответствует четырехугольник ( f ( x j , y i ), f ( x j , y i +1 ), f ( x j +1 , y i +1 ), f ( x j +1 , y i )) в пространстве Oxyz . Будем приближать поверхность z = f ( x , y ) многогранником, состоящим из таких четырехугольников.

Элементом изображения является отрезок. Отрезки выводятся от ближнего к дальним. Для вывода видимой части отрезка используется алгоритм плавающего горизонта (функция sline и vectsec ).

Код на C++
  1. #include <graphics.h>
  2. #include <stdio.h>
  3. #include <math.h>
  4. #include <conio.h>
  5. #define nx 60
  6. #define ny 60
  7.  
  8. float xmax = 3, xmin = -3, ymax = 3, ymin = -3, zmax = 3, zmin = -3;
  9. float xv = 5, yv = 3.5 , zv = 4 ; // положение наблюдателя
  10. float d = 10 ; // расстояние до плоскости проекции
  11. float cosa, sina ; // меридиана точки наблюдения
  12. float exmax, exmin, eymax, eymin ;
  13. int gmex, gmey ;
  14. int fimin[640], fimax[640] ;
  15. float cvals[ny+1], cval ;
  16.  
  17. // Генерация точек отрезка по алгоритму простого ЦДА
  18. void sline( int X0, int Y0, int X1, int Y1 )
  19. {
  20. int i, n;
  21. float x, y, dx=0, dy=0;
  22. n = abs(X1-X0); if (n< abs(Y1-Y0) ) n = abs(Y1-Y0);
  23. if (n>0) {dx=(0.+X1-X0)/n; dy=(0.+Y1-Y0)/n;}
  24. x=X0; y=Y0;
  25. if (dx>0) x+=0.5; else if (dx<0) x-=0.5;
  26. if (dy>0) y+=0.5; else if (dy<0) y-=0.5;
  27. for(i=0;i<=n;i++)
  28. {
  29. if (y>fimax[x]) fimax[x]=y; // Изменяем верхний горизонт
  30. if (y<fimin[x]) fimin[x]=y; // Изменяем нижний горизонт
  31. x+=dx; y+=dy;
  32. }
  33. }
  34.  
  35. // Вывод видимой части отрезка
  36. //с удалением невидимых линий используя алгоритм плавающего горизонта
  37. void vectsec( int X0, int Y0, int X1, int Y1 )
  38. {
  39. int begx, begy, endx, endy, i;
  40. sline(X0, Y0, X1, Y1);
  41. begx=X0; begy=Y0;
  42. endx=X1; endy=Y1;
  43. if (begx>X1) {begx=X1; begy=Y1; endx=X0; endy=Y0;}
  44. moveto( begx, gmey-fimax[begx]);
  45. for (i=begx;i<endx;i++) lineto(i, gmey-fimax[i]);
  46. moveto(begx, gmey-fimin[begx]);
  47. for (i=begx;i<endx;i++) lineto(i, gmey-fimin[i]);
  48. }
  49.  
  50. // Функция z=f(x,y)
  51. float fz(float x, float y) {return (x*sin(y)-y*sin(x));}
  52.  
  53. // Центральная проекция
  54. // x координата на плоскости проекциии
  55. float ex(float x, float y, float z)
  56. {return (-d*(-(x-xv)*sina+(y-yv)*cosa))/((x-xv)*cosa+(y-yv)*sina);}
  57. // y координата на плоскости проекции
  58. float ey ( float x, float y, float z )
  59. {return (-d*(z-zv))/((x-xv)*cosa+(y-yv)*sina);}
  60. // с удалением невидимых линий
  61. // Вычисление экранных координат
  62. void vectfi(float x0, float y0, float z0, float x1, float y1, float z1,int mm)
  63. {
  64. float ex0, ex1, ey0, ey1;
  65. int ix0, ix1, iy0, iy1;
  66. ex0=ex(x0,y0,z0);
  67. ix0=(ex0-exmin)*gmex/(exmax-exmin);
  68. ey0=ey(x0,y0,z0);
  69. iy0=(ey0-eymin)*gmey/(eymax-eymin);
  70. ex1=ex(x1,y1,z1);
  71. ix1=(ex1-exmin)*gmex/(exmax-exmin);
  72. ey1=ey(x1,y1,z1);
  73. iy1=(ey1-eymin)*gmey/(eymax-eymin);
  74.  
  75. // Если mm не равно нулю, то выводим
  76. // изображение с удалением невидимых линий,
  77. // иначе - без удаления невидимых линий
  78. //с удалением невидимых линий используя алгоритм плавающего горизонта
  79. if (mm) vectsec(ix0,iy0,ix1,iy1); else line(ix0,gmey-iy0,ix1,gmey-iy1);
  80. }
  81.  
  82. main()
  83. {
  84. int graphdriver=DETECT, graphmode;
  85. int i, j;
  86. float x,y,hx,hy;
  87.  
  88. // Инициализация графического режима
  89. initgraph(&graphdriver, &graphmode, "");
  90. hy=(ymax-ymin)/ny;
  91. hx=(xmax-xmin)/nx;
  92. gmex=getmaxx(); gmey=getmaxy();
  93. cosa=xv/sqrt(xv*xv+yv*yv);
  94. sina=yv/sqrt(xv*xv+yv*yv );
  95. for(i=0;i<gmex;i++) {fimax[i]=0; fimin[i]=gmey;}
  96. exmax=ex(xmin, ymax, zmax);
  97. exmin=ex(xmax, ymin, zmin);
  98. eymax=ey(xmin, ymin, zmax);
  99. eymin=ey(xmax, ymax, zmin);
  100.  
  101. // Заполнение первой строки
  102. cval=fz(xmax, ymax);
  103. for(i=ny-1;i>=0;i--)
  104. {
  105. cvals[i+1]=cval; y=ymin+hy*i;
  106. cval=fz(xmax, y);
  107. vectfi(xmax, y+hy, cvals[i+1], xmax, y, cval, 1);
  108. }
  109. cvals[0] = cval ;
  110.  
  111. // Заполнение остальных строк
  112. for (j=nx-1;j>=0;j--)
  113. {
  114. x=xmin+hx*j;
  115. cval=fz(x, ymax);
  116. vectfi(x+hx, ymax, cvals[ny], x,ymax,cval, 1);
  117. for(i=ny-1;i>=0;i--)
  118. {
  119. cvals[i+1]=cval; y=ymin+hy*i;
  120. cval=fz(x, y);
  121. vectfi(x, y+hy, cvals[i+1], x, y, cval, 1);
  122. vectfi(x+hx, y, cvals[i], x, y, cval, 1);
  123. }
  124. cvals[0] = cval ;
  125. }
  126.  
  127. // Изображение объемлющего параллелепипеда
  128. vectfi(xmax, ymax, zmax, xmin, ymax, zmax, 0);
  129. vectfi(xmax, ymax, zmax, xmax, ymax, zmin, 0);
  130. vectfi(xmax, ymax, zmax, xmax, ymin, zmax, 0);
  131. vectfi(xmin, ymax, zmin, xmin, ymax, zmax, 0);
  132. vectfi(xmin, ymax, zmin, xmax, ymax, zmin, 0);
  133. vectfi(xmax, ymin, zmin, xmax, ymin, zmax, 0);
  134. vectfi(xmax, ymin, zmin, xmax, ymax, zmin, 0);
  135. vectfi(xmin, ymin, zmin, xmin, ymin, zmax, 1);
  136. vectfi(xmin, ymin, zmin, xmax, ymin, zmin, 1);
  137. vectfi(xmin, ymin, zmin, xmin, ymax, zmin, 1);
  138. vectfi(xmax, ymin, zmax, xmin, ymin, zmax, 1);
  139. vectfi(xmin, ymax, zmax, xmin, ymin, zmax, 1);
  140. getch(); closegraph();
  141. }
При использовании обязательна ссылка на http://DMTSoft.ru
up