3.4. Метод художника

Метод художника — это простой метод изображения поверхностей с удалением невидимых линий.

Пусть поверхность определяется непрерывной функцией z=f(x,y), а переменные x и y изменяются в прямоугольнике на плоскости Oxy: xmin£x£xmax, ymin£y£ymax. Рассматривается прямоугольная сетка в плоскости Oxy с шагом hx=(xmax-xmin)/nx по x, и hy=(ymax-ymin)/ny по y. Каждому прямоугольнику ((xi,yj), (xi,yj+1), (xi+1,yj+1), (xi+1,yj)), 0£j£nx-1, 0£i£ny-1 на плоскости Oxy соответствует четырехугольник (f(xi,yj), f(xi,yj+1), f(xi+1,yj+1), f(xi+1,yj)) в пространстве Oxyz. Будем приближать поверхность z=f(x,y) многогранником, состоящим из таких закрашенных четырехугольников. На экран будем выводить проекции закрашенных четырехугольников.

В методе художника выводятся все закрашенные четырехугольники, а удаление невидимых частей поверхности происходит автоматически за счет порядка вывода закрашенных четырехугольников. Последовательно выводятся все закрашенные четырехугольники, но от дальних к ближним. При этом ранее выведенные на экран невидимые части четырехугольников «закрываются» четырехугольниками, выведенными позже. Элементом изображения в этом методе является закрашенный четырехугольник.

Пример. Если требуется методом художника вывести изображение человека на фоне дерева, то сначала строится закрашенное изображение дерева, включая ту часть дерева, которая позже будет закрыта изображением человека, а затем строится закрашенное изображение человека.

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

Пример реализации алгоритма. В приводимом ниже примере рассматривается параллельная проекция части поверхности, определяемой функцией z=1.2*sin(cos(x+y)-cos(y-x)). Предполагается, что точки (x,y,z) вычерчиваемой части поверхности принадлежат прямоугольному параллелепипеду: xmin£x£xmax, ymin£y£ymax, zmin£z£zmax. Функции ex и ey переводят мировые координаты  (x,y,z) в координаты проекции по формулам:

x¢=-0.2×x+0.4×y,      y¢=-0.1×x+0.2×z.

Наибольшие и наименьшие координаты проекции изображаемого параллелепипеда вычисляются следующим образом:

exmin=ex(xmax,ymin,zmin),exmax=ex(xmin,ymax,zmax),

eymin=ey(xmax,ymax,zmin),eymax=ey(xmin,ymin,zmax).

Прямоугольник exmin£ex£exmax, eymin£ey£eymax будет окном, отображаемым на область вывода, состоящую из точек, имеющих целые координаты

X = (ex-exmin)× mx/(exmax-exmin),      Y = (ey-eymin)× my/(eymax-eymin),

где mx=getmaxx()-10, my=getmaxy()-80

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

Программа

#include<graphics.h>

#include<math.h>

#include<conio.h>

#include<stdlib.h>

#include<dos.h>

#define nx 40

#define ny 40

#define p 3.7

float xmax=p,xmin=-p,ymax=p,ymin=-p,zmax=2*p,zmin=0;

float exmax,exmin,eymax,eymin;

int mx,my,line_color,pol_color;

//функция f по заданной точке на плоскости 0xy

//находит и возвращает координату z

float f(float x,float y) 1.2*sin(cos(x+y)-cos(y-x));

//по данной точке в пространстве находим абсциссу

//точки на плоскости проекции

float ex(float x,float y,float z) return -0.2*x+0.4*y;

//по данной точке в пространстве находим ординату

//точки на плоскости проекции

float ey(float x,float y,float z) return -0.1*x+0.2*z;

//параметрами ф-ции являются координаты вершин четырехугольника

//в пространстве

//Ф-ция осуществляет проекцию этого четырехугольника

//на плоскость и вывод закрашенного четырехугольника на экран компьютера

void vectfi( float x0,float y0,float z0,

           float x1,float y1,float z1, 

           float x2,float y2,float z2, 

           float x3,float y3,float z3) 

{                                        

float ex0,ey0,ex1,ey1,ex2,ey2,ex3,ey3;//координаты точек на плоскости

  //проекции

int far* mas;           //экранные координаты точек

mas=(int far*)malloc(sizeof(int)*8);

//проецирование           

//точек на плоскость       //перевод в экранные координаты

 ex0=ex(x0,y0,z0);         *mas=(ex0-exmin)*mx/(exmax-exmin);

 ey0=ey(x0,y0,z0);         *(mas+1)=my-(ey0-eymin)*my/(eymax-eymin);

 ex1=ex(x1,y1,z1);         *(mas+2)=(ex1-exmin)*mx/(exmax-exmin);

 ey1=ey(x1,y1,z1);         *(mas+3)=my-(ey1-eymin)*my/(eymax-eymin);

 ex2=ex(x2,y2,z2);         *(mas+4)=(ex2-exmin)*mx/(exmax-exmin);

 ey2=ey(x2,y2,z2);         *(mas+5)=my-(ey2-eymin)*my/(eymax-eymin);

 ex3=ex(x3,y3,z3);         *(mas+6)=(ex3-exmin)*mx/(exmax-exmin);

 ey3=ey(x3,y3,z3);         *(mas+7)=my-(ey3-eymin)*my/(eymax-eymin);

 setcolor(line_color);               //установка цвета линии

 setfillstyle(SOLID_FILL,pol_color); //установка типа и цвета заливки

 fillpoly(4,mas);                 //рисование закрашенного четырехугольника

}

void main(void)

{

 int gd=DETECT,gm,i,j;

 float x1,y1,x2,y2,x3,y3,x4,y4,hx,hy;

 initgraph(&gd,&gm,"..\BGI");     //установка графического режима

 mx=getmaxx()-10; my=getmaxy()-80;

 setcolor(RED); setfillstyle(SOLID_FILL,WHITE);

 hy=(ymax-ymin)/ny;     //шаг по y

 hx=(xmax-xmin)/nx;     //шаг по x

exmax=ex(xmin,ymax,zmax); //вычисляем наибольшие и

 exmin=ex(xmax,ymin,zmin); //наименьшие координаты на плоскости

 eymax=ey(xmin,ymin,zmax); //проекции

 eymin=ey(xmax,ymax,zmin);

 line_color=WHITE; pol_color=BLACK;

 //вывод трех граней объемлющего параллелепипеда

 vectfi(xmin,ymax,zmax,xmin,ymax,zmin,xmin,ymin,zmin,xmin,ymin,zmax);

 vectfi(xmin,ymin,zmin,xmin,ymin,zmax,xmax,ymin,zmax,xmax,ymin,zmin);

 vectfi(xmin,ymax,zmin,xmin,ymin,zmin,xmax,ymin,zmin,xmax,ymax,zmin);

 line_color=WHITE;pol_color=RED;

 for(j=0;j<=ny-1;j++)        //в цикле последовательно вычисляются

  {                          //координаты вершин прямоугольников

      y1=j*hy+ymin;          //на плоскости Oxy от дальних к ближним и

      y2=j*hy+ymin;          //вызывается функция vectfi

      y3=(j+1)*hy+ymin;    

      y4=(j+1)*hy+ymin;

      for(i=0;i<=nx-1;i++)

       {

        x1=i*hx+xmin;

        x2=(i+1)*hx+xmin;

        x3=(i+1)*hx+xmin;

        x4=i*hx+xmin;

        delay(1);            //задержка на 1 милисекунду

        vectfi(x1,y1,f(x1,y1),x2,y2,f(x2,y2),x3,y3,f(x3,y3),x4,y4,f(x4,y4));

       }

  }

getch(); closegraph();

}

Результат работы программы