📄 graph3d.c
字号:
/* * Copyright (c) 1999 Greg Haerr <greg@censoft.com> * * 3D Graphics Library for Micro-Windows */#define MWINCLUDECOLORS#include "windows.h"#include "device.h"#include "graph3d.h"#define USEBLIT 1 /* =1 to use memDC's*/static int nxpix;static int nypix;static vec1 xscale;static vec1 yscale;static vec3 eye;static vec3 direct;static double Q[5][5];static HDC hdc;static HDC hdcMem;static HBITMAP hbmp, hbmpOrg;/* setup eye, direction, calc observation matrix Q*/voidlook3(vec1 x, vec1 y, vec1 z){ eye.x = x; eye.y = y; eye.z = z; direct.x = -eye.x; direct.y = -eye.y; direct.z = -eye.z; findQ();}voidinit3(HDC hDC, HWND memhwnd){ HBRUSH hbr; hdc = hDC; if(hdc) { nxpix = hdc->hwnd->clirect.right - hdc->hwnd->clirect.left; nypix = hdc->hwnd->clirect.bottom - hdc->hwnd->clirect.top; xscale = (vec1)(nxpix-1) / nxpix * nxpix/2; yscale = (vec1)(nypix-1) / nypix * nypix/2; if(memhwnd) { hdcMem = CreateCompatibleDC(NULL); if(hdcMem) { hbmp = CreateCompatibleBitmap(hdcMem, nxpix, nypix); hbmpOrg = SelectObject(hdcMem, hbmp); hdc = hdcMem; } hbr = (HBRUSH)GetClassLong(memhwnd, GCL_HBRBACKGROUND); FillRect(hdc, NULL, hbr); } /* create pen for setcolor3() color override*/ SelectObject(hdc, CreatePen(PS_SOLID, 1, BLACK)); }}voidpaint3(HDC hDC){ if(hdcMem) { BitBlt(hDC, 0, 0, nxpix, nypix, hdcMem, 0, 0, SRCCOPY); DeleteObject(SelectObject(hdcMem, hbmpOrg)); DeleteDC(hdcMem); } hdcMem = NULL;}intfx(vec1 x){ return (int)(x * xscale + nxpix*0.5 - 0.5);}intfy(vec1 y){ return (int)(y * yscale + nypix*0.5 - 0.5);}voidmoveto3(vec2 pt){ MoveToEx(hdc, fx(pt.x), fy(pt.y), NULL);}voidsetcolor3(MWCOLORVAL c){ if(hdc) hdc->pen->color = c;}voidlineto3(vec2 pt){ LineTo(hdc, fx(pt.x), fy(pt.y));}voidpolyfill(int n, vec2 points[]){ int i; int xoff, yoff; MWPOINT pv[MAXPOLY]; if(!hdc) return; /* calc window offset*/ xoff = hdc->hwnd->clirect.left; yoff = hdc->hwnd->clirect.top; /* only plot non-trivial polygons*/ if(n > 2) { for(i=0; i<n; ++i) { pv[i].x = fx(points[i].x) + xoff; pv[i].y = fy(points[i].y) + yoff; /* fix: floating round error, y intercept difference * with GdLine */ /*pv[i].x = fx(points[i].x + xoff);*/ /*pv[i].y = fy(points[i].y + yoff);*/ } GdSetForeground(GdFindColor(hdc->pen->color)); GdFillPoly(hdc->psd, n, pv); }}voidsquare(void){ vec2 pt0, pt1, pt2, pt3; pt0.x = -1; pt0.y = 1; pt1.x = -1; pt1.y = -1; pt2.x = 1; pt2.y = -1; pt3.x = 1; pt3.y = 1; moveto3(pt0); lineto3(pt1); lineto3(pt2); lineto3(pt3); lineto3(pt0);}voidcircle3(vec1 r){ vec1 theta = 0; vec1 thinc = 2*pi/100; int i; vec2 pt; pt.x = r; pt.y = 0.0; moveto3(pt); for(i=0; i<100; ++i) { theta = theta + thinc; pt.x = r*cos(theta); pt.y = r*sin(theta); lineto3(pt); }}voiddaisy(vec1 r,int points){ int i, j; vec1 theta = 0; vec1 thinc; vec2 pt[100]; /* calculate n points on a circle*/ thinc = 2*pi/points; for(i=0; i<points; ++i) { pt[i].x = r*cos(theta); pt[i].y = r*sin(theta); theta += thinc; } /* join point i to point j for all 0 <= i < j < n */ for(i=0; i<points-1; ++i) { for(j=i+1; j<points; ++j) { moveto3(pt[i]); lineto3(pt[j]); } }}voidrose(vec1 r,int levels,int points){ int i, j, m, n; vec1 r1, theta, thinc; vec2 inner[100]; vec2 outer[100]; vec2 triangle[3]; m = levels; n = points; thinc = 2*pi/n; /* initial inner circle*/ for(i=0; i<n; ++i) { inner[i].x = 0.0; inner[i].y = 0.0; } /* loop thru m levels*/ for(j=1; j<=m; ++j) { theta = -j*pi/n; r1 = r * (vec1)j/m; /* calc n points on outer circle*/ for(i=0; i<n; ++i) { theta += thinc; outer[i].x = r1*cos(theta); outer[i].y = r1*sin(theta); } /* construct/draw triangles with vertices on * inner and outer circles */ for(i=0; i<n; ++i) { triangle[0] = outer[i]; triangle[1] = outer[(i+1) % n]; triangle[2] = inner[i]; /* fill triangle in red*/ setcolor3(RED); polyfill(3, triangle);#if 1 /* outline triangle in white*/ setcolor3(WHITE); moveto3(triangle[0]); lineto3(triangle[1]); lineto3(triangle[2]); lineto3(triangle[0]);#endif } /* copy points on outer circle to inner arrays*/ for(i=0; i<n; ++i) inner[i] = outer[i]; }}/* draw a triangle with cordners v0, v1, v2*/voidtriangle(vec2 v0, vec2 v1, vec2 v2){ vec2 poly[3]; poly[0] = v0; poly[1] = v1; poly[2] = v2; setcolor3(GREEN); polyfill(3, poly); setcolor3(BLACK); moveto3(poly[2]); lineto3(poly[0]); lineto3(poly[1]); lineto3(poly[2]);}/* draw a quadrilateral with corners v0, v1, v2, v3*/voidquadrilateral(vec2 v0, vec2 v1, vec2 v2, vec2 v3){ vec2 poly[4]; poly[0] = v0; poly[1] = v1; poly[2] = v2; poly[3] = v3; setcolor3(GREEN); polyfill(4, poly); setcolor3(BLACK); moveto3(poly[3]); lineto3(poly[0]); lineto3(poly[1]); lineto3(poly[2]); lineto3(poly[3]);}/* find intersection of lines v0 to v1 and v2 to v3*/static intpatch(vec2 v0, vec2 v1, vec2 v2, vec2 v3){ vec1 denom; vec1 mu; vec2 v4; denom = (v1.x-v0.x)*(v3.y-v2.y) - (v1.y-v0.y)*(v3.x-v2.x); if(fabs(denom) > epsilon) { mu = ((v2.x-v0.x)*(v3.y-v2.y) - (v2.y-v0.y)*(v3.x-v2.x))/denom; /* if intersection between lines v0 to v1 and v2 to v3, * call it v4 and form triangles v0,v2,v4 and v1,v3,v4 */ if(mu >= 0 && mu <= 1) { v4.x = (1-mu)*v0.x + mu*v1.x; v4.y = (1-mu)*v0.y + mu*v1.y; triangle(v0, v2, v4); triangle(v1, v3, v4); return 0; } } /* else find intersection of lines v0 to v2 and v1 to v3*/ denom = (v2.x-v0.x)*(v3.y-v1.y) - (v2.y-v0.y)*(v3.x-v1.x); if(fabs(denom) > epsilon) { mu = ((v1.x-v0.x)*(v3.y-v1.y) - (v1.y-v0.y)*(v3.x-v1.x))/denom; /* if intersection between v0 and v1, call it v4 * and form triangles v0,v1,v4 and v2,v3,v4 */ if(mu >= 0 && mu <= 1) { v4.x = (1-mu)*v0.x + mu*v2.x; v4.y = (1-mu)*v0.y + mu*v2.y; triangle(v0, v1, v4); triangle(v2, v3, v4); return 0; } } /* there are no proper intersections so form quadrilateral v0,v1,v3,v2*/ quadrilateral(v0, v1, v3, v2); return 1;}/* plotted function*/static vec1plotfn(vec1 x, vec1 z){ vec1 t; /* y = 4sin(sqrt(x*x+z*z))/sqrt(x*x+z*z) */ t = sqrt(x*x + z*z); if(fabs(t) < epsilon) return 4.0; return 4.0 * sin(t) / t;}/* draw mathematical function plotfn*/voiddrawgrid(vec1 xmin, vec1 xmax, int nx, vec1 zmin, vec1 zmax, int nz){ int i, j; vec1 xi, xstep, yij; vec1 zj, zstep; vec2 v[2][100]; double S[5][5]; /* scale it down*/ scale3(1.0/(xmax-xmin)*2, 1.0/(xmax-xmin)*2, 1.0/(zmax-zmin), S); mult3(Q, S, Q); /* grid from xmin to xmax in nx steps and zmin to xmax in nz steps*/ xstep = (xmax-xmin)/nx; zstep = (zmax-zmin)/nz; xi = xmin; zj = zmin; /* calc grid points on first fixed-z line, fine the y-height * and transfrorm the points (xi,yij,zj) into observed * position. Observed first set stored in v[0,1..nx] */ for(i=0; i<=nx; ++i) { yij = plotfn(xi, zj); v[0][i].x = Q[1][1]*xi + Q[1][2]*yij + Q[1][3]*zj; v[0][i].y = Q[2][1]*xi + Q[2][2]*yij + Q[2][3]*zj; xi += xstep; } /* run thru consecutive fixed-z lines (the second set)*/ for(j=0; j<nz; ++j) { xi = xmin; zj += zstep; /* calc grid points on this second set, find the * y-height and transform the points (xi,yij,zj) * into observed position. Observed second set * stored in v[1,0..nx] */ for(i=0; i<=nx; ++i) { yij = plotfn(xi, zj); v[1][i].x = Q[1][1]*xi + Q[1][2]*yij + Q[1][3]*zj; v[1][i].y = Q[2][1]*xi + Q[2][2]*yij + Q[2][3]*zj; xi += xstep; } /* run thru the nx patches formed by these two sets*/ for(i=0; i<nx; ++i) patch(v[0][i], v[0][i+1], v[1][i], v[1][i+1]); /* copy second set into first set*/ for(i=0; i<=nx; ++i) v[0][i] = v[1][i]; }}/* returns the angle whose tangent is y/x. * all anomalies such as x=0 are also checked */vec1angle(vec1 x, vec1 y){ if(fabs(x) < epsilon) if(fabs(y) < epsilon) return 0.0; else if(y > 0.0) return pi*0.5; else return pi*1.5; else if(x < 0.0) return atan(y/x) + pi; else return atan(y/x);}/* calc 3d scaling matrix A giving scaling vector sx,sy,sz. * one unit on the x axis becomes sx units, one unit on y, sy, * and one unit on the z axis becomes sz units */voidscale3(vec1 sx, vec1 sy, vec1 sz, double A[][5]){ int i, j; for(i=1; i<5; ++i) for(j=1; j<5; ++j) A[i][j] = 0.0; A[1][1] = sx; A[2][2] = sy; A[3][3] = sz; A[4][4] = 1.0;}/* calc 3d axes translation matrix A * origin translated by vectdor tx,ty,tz */voidtran3(vec1 tx, vec1 ty, vec1 tz, double A[][5]){ int i, j; for(i=1; i<5; ++i) { for(j=1; j<5; ++j) A[i][j] = 0.0; A[i][i] = 1.0; } A[1][4] = -tx; A[2][4] = -ty; A[3][4] = -tz;}/* calc 3d axes rotation matrix A. The axes are * rotated anti-clockwise through an angle theta radians * about an axis specified by m: m=1 means x, m=2 y, m=3 z axis */voidrot3(int m, vec1 theta, double A[][5]){ int i, j, m1, m2; vec1 c, s; for(i=1; i<5; ++i) for(j=1; j<5; ++j) A[i][j] = 0.0; A[m][m] = 1.0; A[4][4] = 1.0; m1 = (m % 3) + 1; m2 = (m1 % 3) + 1; c = cos(theta); s = sin(theta); A[m1][m1] = c; A[m2][m2] = c; A[m1][m2] = s; A[m2][m1] = s;}/* calc the matrix product C of two matrices A and B*/voidmult3(double A[][5], double B[][5], double C[][5]){ int i, j, k; vec1 ab; for(i=1; i<5; ++i) for(j=1; j<5; ++j) { ab = 0; for(k=1; k<5; ++k) ab += A[i][k] * B[k][j]; C[i][j] = ab; }}/* calc observation matrix Q for given observer*/voidfindQ(void){ vec1 alpha, beta, gamma, v, w; double E[5][5]; double F[5][5]; double G[5][5]; double H[5][5]; double U[5][5]; /* calc translation matrix F*/ tran3(eye.x, eye.y, eye.z, F); /* calc rotation matrix G*/ alpha = angle(-direct.x, -direct.y); rot3(3, alpha, G); /* calc rotation matrix H*/ v = sqrt(direct.x*direct.x + direct.y*direct.y); beta = angle(-direct.z, v); rot3(2, beta, H); /* calc rotation matrix U*/ w = sqrt(v*v + direct.z*direct.z); gamma = angle(-direct.x*w, direct.y*direct.z); rot3(3, -gamma, U); /* combine the transformations to find Q*/ mult3(G, F, Q); mult3(H, Q, E); mult3(U, E, Q);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -