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


Добавил:DMT
Дата создания:4 декабря 2007, 3:15
Дата обновления:4 декабря 2007, 3:15
Просмотров:6021 последний сегодня, 14:27
Комментариев: 0

Удаление невидимых линий осуществляется с использованием алгоритма плавающего горизонта. Рассматривается  параллельная проекция. Поверхность задается одной формулой: Z=x*y/(x^2+y^2+1).

 

Исходный текст программы на языке C Builder:

//---------------------------------------------------------------------------

#include <vcl.h>

#include <math.h>

#pragma hdrstop

#include "Unit1.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

#define nx 60

#define ny 60

float xmax = 3, xmin = -3, ymax = 3, ymin = -3, zmax = 3, zmin = -2;

float xv = 5, yv = 3.5 , zv = 3 ; // положение наблюдателя

float d = 10 ; // расстояние до плоскости проекции

float cosa, sina ; // меридиана точки наблюдения

float exmax, exmin, eymax, eymin ;

int gmex, gmey ;

int fimin[640], fimax[640] ;

float cvals[ny+1], cval ;

void sline( int X0, int Y0, int X1, int Y1 )

{

int i, n;

float x, y, dx=0, dy=0;

n = abs(X1-X0); if (n< abs(Y1-Y0) ) n = abs(Y1-Y0);

if (n>0) {dx=(0.+X1-X0)/n; dy=(0.+Y1-Y0)/n;}

x=X0; y=Y0;

if (dx>0) x+=0.5; else if (dx<0) x-=0.5;

if (dy>0) y+=0.5; else if (dy<0) y-=0.5;

for(i=0;i<=n;i++)

{

if (y>fimax[(int)x]) fimax[(int)x]=y; // Изменяем верхний горизонт

if (y<fimin[(int)x]) fimin[(int)x]=y; // Изменяем нижний горизонт

x+=dx; y+=dy;

}

}

// Вывод видимой части отрезка

void vectsec( int X0, int Y0, int X1, int Y1 )

{

int begx, begy, endx, endy, i;

sline(X0, Y0, X1, Y1);

begx=X0; begy=Y0;

endx=X1; endy=Y1;

if (begx>X1) {begx=X1; begy=Y1; endx=X0; endy=Y0;}

Form1->Canvas->MoveTo( begx, gmey-fimax[begx]);

for (i=begx;i<endx;i++) Form1->Canvas->LineTo(i, gmey-fimax[i]);

Form1->Canvas->MoveTo(begx, gmey-fimin[begx]);

for (i=begx;i<endx;i++) Form1->Canvas->LineTo(i, gmey-fimin[i]);

}

/*

x'=-d(r-r0) u1 / ((r-r0) u - d);

y'=-d(r-r0) u2 / ((r-r0) u - d);

z'=- =d/((r-r0) u - d).

float fz(float x, float y) {return (x*y/(x*x+y*y+1));}

// Центральная проекция

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

float ex(float x, float y, float z)

{return (-d*(-(x-xv)*sina+(y-yv)*cosa))/((x-xv)*cosa+(y-yv)*sina);}

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

float ey(float x, float y, float z )

{return (-d*(z-zv))/((x-xv)*cosa+(y-yv)*sina);}

*/

float fz(float x, float y) {return (x*y/(x*x+y*y+1));}

// Центральная проекция

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

float ex(float x, float y, float z)

{return (-d*(-(x-xv)*sina+(y-yv)*cosa))/((x-xv)*cosa+(y-yv)*sina);}

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

float ey(float x, float y, float z )

{return (-d*(z-zv))/((x-xv)*cosa+(y-yv)*sina);}

// Вычисление экранных координат

void vectfi(float x0, float y0, float z0, float x1, float y1, float z1,int mm)

{

float ex0, ex1, ey0, ey1;

int ix0, ix1, iy0, iy1;

ex0=ex(x0,y0,z0);

ix0=(ex0-exmin)*gmex/(exmax-exmin);

ey0=ey(x0,y0,z0);

iy0=(ey0-eymin)*gmey/(eymax-eymin);

ex1=ex(x1,y1,z1);

ix1=(ex1-exmin)*gmex/(exmax-exmin);

ey1=ey(x1,y1,z1);

iy1=(ey1-eymin)*gmey/(eymax-eymin);

// Если mm не равно нулю, то выводим

// изображение с удалением невидимых линий,

// иначе - без удаления невидимых линий

if (mm) vectsec(ix0,iy0,ix1,iy1); else {

Form1->Canvas->MoveTo(ix0,gmey-iy0);

Form1->Canvas->LineTo(ix1,gmey-iy1);

}

}

 

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

//---------------------------------------------------------------------------

void __fastcall TForm1::FormClick(TObject *Sender)

{

int i, j;

float x,y,hx,hy;

Form1->Canvas->Pen->Color=clWhite;

Form1->Canvas->Brush->Color=clWhite;

Form1->Canvas->Rectangle(0,0,Form1->ClientWidth,Form1->ClientHeight);

Form1->Canvas->Pen->Color=clBlack;

hy=(ymax-ymin)/ny;

hx=(xmax-xmin)/nx;

gmex=Form1->ClientWidth; gmey=Form1->ClientHeight;

cosa=xv/sqrt(xv*xv+yv*yv);

sina=yv/sqrt(xv*xv+yv*yv );

for(i=0;i<gmex;i++) {fimax[i]=0; fimin[i]=gmey;}

exmax=ex(xmin, ymax, zmax);

exmin=ex(xmax, ymin, zmin);

eymax=ey(xmin, ymin, zmax);

eymin=ey(xmax, ymax, zmin);

// Заполнение первой строки

cval=fz(xmax, ymax);

for(i=ny-1;i>=0;i--)

{

cvals[i+1]=cval; y=ymin+hy*i;

cval=fz(xmax, y);

vectfi(xmax, y+hy, cvals[i+1], xmax, y, cval, 1);

}

cvals[0] = cval ;

// Заполнение остальных строк

for (j=nx-1;j>=0;j--)

{

x=xmin+hx*j;

cval=fz(x, ymax);

vectfi(x+hx, ymax, cvals[ny], x,ymax,cval, 1);

for(i=ny-1;i>=0;i--)

{

cvals[i+1]=cval; y=ymin+hy*i;

cval=fz(x, y);

vectfi(x, y+hy, cvals[i+1], x, y, cval, 1);

vectfi(x+hx, y, cvals[i], x, y, cval, 1);

}

cvals[0] = cval ;

}

// Изображение объемлющего параллелепипеда

vectfi(xmax, ymax, zmax, xmin, ymax, zmax, 0);

vectfi(xmax, ymax, zmax, xmax, ymax, zmin, 0);

vectfi(xmax, ymax, zmax, xmax, ymin, zmax, 0);

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

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

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

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

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

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

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

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

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

}

//---------------------------------------------------------------------------

up