第六章 多邊型繪圖

advertisement
第六章 多邊型繪圖
作者: 南台科技大學 電子系
黎靖
1. 座標系統:
2. 繪製立體圖
// viewing.cpp : viewing
#include "Marco_Lee.h"
#include "Graph_Lee.h"
Point3 Viewing(Point3);
void Coeff(float, float, float);
float v11, v12, v13, v21, v22, v23, v32, v33, v43;
void main()
{
Point3 P[] = {
{100,80,50,0}, {100,0,50,1}, {100,0,0,1},
{100,80,0,1},
{0,80,0, 1}, {0,80,50,1},
{100,80,50,1}, {100,80,0,1},
{100,0,50,0}, {0,0,50,1},
{0,0,50,0},
{0,80,50,1},
{100,0,50,0}, {100,40,80,1},
{0,40,80,1}, {0,80,50,1},
{100,50,72,0}, {100,50,90,1},
{80,65, 61,1}, {80,65,90,1},
{100,65,90,0}, {80,65,90,1},
{80,65,61,1}, {100,50,72,0},
{0,0,0,1},
{0,0,0,0},
{100,80,50,1},
{100,40,80,0},
{100,65,90,1},
{80,50,90,1},
{80,50,90,0},
{80,50,72,1},
1
{100,0,0,1},
{0,80,0,1},
{0,0,50,0},
{0,40,80,1},
{100,65,61,1},
{100,50,90,1},
{80,50,72,1},
{0,0,0,-999}};
Point3 p1, p2;
float rho = 500, theta = 50, phi = 70;
setWorkSpace(-100, -100, 100, 100); // x1, y1, x2, y2
setViewSpace(1, 1, 9, 7);
Coeff(rho, theta, phi);
setWindow();
for (int k=0; P[k].connect != -999; k++)
{
p2 = Viewing(P[k]);
if (0 != P[k].connect) DrawLine(p1, p2, 0, black);
p1 = p2;
}
viewWindow(); closeWindow();
}
void Coeff(float rho, float theta, float phi)
{
double costh, sinth, cosph, sinph;
costh = COS(theta); sinth = SIN(theta);
cosph = COS(phi);
sinph = SIN(phi);
// Elements of matrix V, see Eq. (4-9):
//p.127
v11 = -sinth; v12 = -cosph*costh;
v13 = -sinph*costh;
v21 = costh; v22 = -cosph * sinth; v23 = -sinph*sinth;
v32 = sinph;
v33= -cosph;
v43 = rho;
}
/******************************************************************/
Point3 Viewing(Point3 P) // p.127
{
Point3 T;
// Eye coordinates, computed as in Eq. (4-2):
T.x = v11*P.x + v21*P.y;
T.y = v12*P.x + v22*P.y + v32*P.z;
T.z = v13*P.x + v23*P.y + v33*P.z + v43;
return T;
}
2
3. 加入視角的考慮
// perspective.cpp :
#include "Marco_Lee.h"
#include "Graph_Lee.h"
Point3 Perspective(Point3);
void Coeff(float, float, float);
float v11, v12, v13, v21, v22, v23, v32, v33, v43;
float screen_dist=200, c1 = 50, c2 = -10;
void main()
{
Point3 P[] = {
{100,80,50,0}, {100,0,50,1},
{0,80,0, 1}, {0,80,50,1},
{100,0,50,0}, {0,0,50,1},
{0,0,50,0},
{0,80,50,1},
{100,0,50,0}, {100,40,80,1},
{0,40,80,1}, {0,80,50,1},
{100,50,72,0}, {100,50,90,1},
{100,0,0,1},
{100,80,50,1},
{0,0,0,1},
{0,0,0,0},
{100,80,50,1},
{100,40,80,0},
{100,65,90,1},
{100,80,0,1},
{100,80,0,1},
{100,0,0,1},
{0,80,0,1},
{0,0,50,0},
{0,40,80,1},
{100,65,61,1},
{80,65, 61,1}, {80,65,90,1}, {80,50,90,1}, {100,50,90,1},
{100,65,90,0}, {80,65,90,1}, {80,50,90,0}, {80,50,72,1},
{80,65,61,1}, {100,50,72,0}, {80,50,72,1}, {0,0,0,-999}};
Point3 p1, p2;
float rho = 300, theta = 50, phi = 70;
setWorkSpace(-100, -100, 100, 100);
setViewSpace(1, 1, 9, 7);
Coeff(rho, theta, phi);
// x1, y1, x2, y2
3
setWindow();
for (int k=0; P[k].connect != -999; k++)
{
p2 = Perspective(P[k]);
if (0 != P[k].connect) DrawLine(p1, p2, 0, black);
p1 = p2;
}
viewWindow(); closeWindow();
}
void Coeff(float rho, float theta, float phi)
//p.127
{
double costh, sinth, cosph, sinph;
costh = COS(theta); sinth = SIN(theta);
cosph = COS(phi);
sinph = SIN(phi);
// Elements of matrix V, see Eq. (4-9):
v11 = -sinth; v12 = -cosph*costh;
v13 = -sinph*costh;
v21 = costh; v22 = -cosph * sinth; v23 = -sinph*sinth;
v32 = sinph;
v33= -cosph;
v43 = rho;
}
/******************************************************************/
Point3 Perspective(Point3 P) // p.127
{
Point3 T, Pe;
// Eye coordinates, computed as in Eq. (4-2):
T.x = v11*P.x + v21*P.y;
T.y = v12*P.x + v22*P.y + v32*P.z;
T.z = v13*P.x + v23*P.y + v33*P.z + v43;
// Screen coordinates, computed as in Eqs. (4-12) and (4.13)
Pe.x = screen_dist * T.x/T.z + c1;
Pe.y = screen_dist * T.y/T.z + c2;
return Pe;
}
screen_dist=500, c1 = 50, c2 = -10;
rho = 400, theta = 50, phi = 70;
4
4. 隱藏線處理 (simple)
// common.h
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include "d_draw.h"
#include "d_linesh.h"
// openWindow(); viewWindow(); closeWindow();
// lineShape class
#define MAX(x,y)
((x) > (y)? (x) : (y))
#define MIN(x,y)
((x) < (y)? (x) : (y))
#define MAX3(x,y,z) ((x)>(y)? MAX((x),(z)): MAX((y),(z)))
#define MIN3(x,y,z) ((x)<(y)? MIN((x),(z)): MIN((y),(z)))
#define SWAP(aux, a, b) { (aux) = (a); (a) = (b); (b) = (aux); }
#define SWAP3(aux,a,b,c) { (aux) = (a); (a) = (b); (b) = (c); (c) = (aux); }
#define SIGN(x)
((x) > eps ? 1: (x) < meps ? -1: 0)
#define RD (0.0174533) // RD = 3.14159/180
#define BIG 1.e30
typedef int INDEX;
typedef float COEF;
typedef float DEGREE;
struct POSI { float x, y, z; };
struct WorkSpace { float x1, y1, x2, y2; } WS;
struct ViewSpace {float x1, y1, x2, y2;} VS;
5
POSI Viewing(POSI P);
void Coeff();
DEGREE rho, theta, phi;
COEF v11, v12, v13, v21, v22, v23, v32, v33, v43;
/******************************************************************/
void Coeff()
//p.127
{
double th, ph, costh, sinth, cosph, sinph;
// angles in radians:
th = theta*RD; ph = phi*RD;
costh = cos(th); sinth = sin(th);
cosph = cos(ph); sinph = sin(ph);
// Elements of matrix V, see Eq. (4-9):
v11 = -sinth; v12 = -cosph*costh;
v13 = -sinph*costh;
v21 = costh; v22 = -cosph * sinth; v23 = -sinph*sinth;
v32 = sinph;
v33= -cosph;
v43 = rho;
}
/******************************************************************/
POSI Viewing(POSI P)
// p.127
{
POSI T;
// Eye coordinates, computed as in Eq. (4-2):
T.x = v11*P.x + v21*P.y;
T.y = v12*P.x + v22*P.y + v32*P.z;
T.z = v13*P.x + v23*P.y + v33*P.z + v43;
return T;
}
// Hidlin1.cpp : A simple program for hidden-line elimination
// The output of this program is the file A.SCRATCH,
// which is to be read by GENPLOT.
#include "common.h"
#define nvertex 200 // Max no of vertices
#define ntriangle 200 // Max no of (no backface) triangles to be stored
6
struct Tria { int A, B, C; float a, b, c, h;} ;
void ReadData();
void skipf();
int reflo(float *px);
int reint(int *pi);
void error(char *str);
void linesegment(POSI, POSI, int);
int ntr=0;
float eps=1e-5, meps=-1e-5, oneminus=1-1.e-5, oneplus=1+1.e-5;
POSI Vx[nvertex];
Tria TRI[ntriangle];
FILE *fin, *fout;
/******************************************************************/
void main()
{
int i, j;
fin = fopen("a.dat", "r");
fout = fopen("a.scratch","w");
if (fout == NULL) error("file a.scratch cannot be opened");
ReadData();
while (skipf(), fscanf(fin, "%d %d", &i, &j))
{
linesegment(Vx[i], Vx[j], 0);
}
fclose(fout);
}
void ReadData()
{
int i; float r;
POSI Or, P, A, B, C;
Tria t;
char ch;
fscanf(fin, "%f %f %f", &(Or.x), &(Or.y), &(Or.z));
skipf();
fscanf(fin, "%f %f %f", &rho, &theta, &phi);
Coeff();
while (skipf(), ch=getc(fin), ch != '#')
{
7
ungetc(ch, fin);
fscanf(fin, "%d %f %f %f", &i, &(P.x), &(P.y), &(P.z));
if (i < 0 || i >= nvertex) error("illegal vertex number");
P.x -= Or.x; P.y -= Or.y; P.z -= Or.z;
Vx[i] = Viewing(P);
if (Vx[i].z <= eps)
{
printf("Object point 0 and vertex %d lie on ", i);
error("different sides of viewpoint E.");
}
}
while (skipf(), ch=getc(fin), ch != '#')
{
ungetc(ch, fin);
fscanf(fin, "%d %d %d", &(t.A), &(t.B), &(t.C));
A = Vx[t.A];
B = Vx[t.B];
C = Vx[t.C];
t.a = A.y *(B.z-C.z) - B.y * (A.z-C.z) + C.y*(A.z-B.z);
t.b = -(A.x *(B.z-C.z) - B.x * (A.z-C.z) + C.x*(A.z-B.z));
t.c = A.x *(B.y-C.y) - B.x * (A.y-C.y) + C.x*(A.y-B.y);
t.h = A.x *(B.y*C.z - C.y*B.z) - B.x *(A.y*C.z - C.y*A.z) +
C.x *(A.y*B.z - B.y*A.z);
if (t.h > 0)
{
if (ntr == ntriangle) error("Too many triangles");
r = sqrt(t.a*t.a + t.b*t.b + t.c*t.c);
t.a /= r; t.b /= r; t.c /= r; t.h /= r;
TRI[ntr++] = t;
}
}
}
void skipf() {
while(getc(fin) != '\n');}
void error(char *str) {
printf("%s\n", str); exit(1); }
void linesegment(POSI P, POSI Q, int k0)
{
// line segment PQ is to be drawn, as far as it is not hidden by the
// triangles trset[k0] to trset[ntrset-1].
8
bool worktodo = 1, Pbeyond, Qbeyond, outside,
Poutside, Qoutside;
POSI A, B, C, T;
int k=k0, ia, ib, ic, i, sum;
float a, b, c, h, hP, hQ, r1, r2, r3, dA, dB, dC, labmin, labmax,
lab, mu, xmin, ymin, zmin, xmax, ymax, zmax, c1, c2, c3,
k1, k2, k3, denom1, denom2, Cpos, Ppos, Qpos, aux, eps1;
while (k < ntr)
{
a = TRI[k].a;
b = TRI[k].b; c = TRI[k].c;
h = TRI[k].h;
eps1 = eps + eps*h;
// Test 1:
hP = a*P.x + b*P.y + c*P.z;
hQ = a*Q.x + b*Q.y + c*Q.z;
if (hP <= h+eps1 && hQ <= h+eps1) // PQ not behind ABC
{
k++; continue; }
// Test 2:
k1 = P.y*Q.z - Q.y*P.z;
k3 = P.x*Q.y - Q.x*P.y;
k2 = P.z*Q.x - Q.z*P.x;
ia = TRI[k].A; ib = TRI[k].B; ic = TRI[k].C;
A = Vx[ia];
B = Vx[ib];
C = Vx[ic];
dA = k1*A.x + k2*A.y + k3*A.z; dB = k1*B.x + k2*B.y + k3*B.z;
dC = k1*C.x + k2*C.y + k3*C.z;
// If dA, dB, dC have the same sign, the vertices A, B, C
// lie at the same side of plane EPQ.
sum = SIGN(dA)+SIGN(dB)+SIGN(dC);
if (abs(sum) >= 2) { k++; continue; }
// If this test succeeds, the (infinite) line PQ lies outside
// pyramid EABC (or the line and the pyramid have at most one
// point in common). If the test fails, there is a point of
// intersection.
// Test 3:
Poutside = Qoutside = 0; labmin = 1.; labmax = 0.;
for (i=0; i<3; i++)
{
9
c1 = A.y*B.z-B.y*A.z; c2 = A.z*B.x-B.z*A.x;
c3 = A.x*B.y-B.x*A.y;
// c1 x + c2 y + c3 z = 0 is plane EAB
Cpos = c1*C.x + c2*C.y + c3*C.z;
Ppos = c1*P.x + c2*P.y + c3*P.z;
Qpos = c1*Q.x + c2*Q.y + c3*Q.z;
denom1 = Qpos - Ppos;
if (Cpos > eps)
{
Pbeyond = Ppos < meps; Qbeyond = Qpos < meps;
outside = (Pbeyond && Qpos<=eps) ||
(Qbeyond && Ppos <= eps);
}
else if (Cpos < meps)
{
Pbeyond = Ppos > eps; Qbeyond = Qpos > eps;
outside = (Pbeyond && Qpos>= meps) ||
(Qbeyond && Ppos >= meps);
}
else outside = 1;
if (outside) break;
lab = fabs(denom1)<=eps ? 1.e7 : -Ppos/denom1;
// lab indicates where PQ meets plane EAB
Poutside |= Pbeyond;
Qoutside |= Qbeyond;
denom2 = dB-dA;
mu = (fabs(denom2)<=eps ? 1.e7 : -dA/denom2);
// mu tells where AB meets plane EPQ
if (mu >= meps && mu <= oneplus && lab >= meps && lab <= oneplus)
{
labmin = MIN(lab, labmin);
labmax = MAX(lab, labmax);
}
SWAP3(T, A, B, C);
SWAP3(aux, dA, dB, dC);
}
if (outside) { k++; continue; }
// Test 4:
if (!(Poutside || Qoutside)) {worktodo = 0; break; }// PQ invisible
//
Test 5:
10
r1 = Q.x - P.x; r2 = Q.y - P.y; r3 = Q.z - P.z;
xmin = P.x + labmin*r1;
ymin = P.y + labmin*r2;
zmin = P.z + labmin*r3;
if (a*xmin + b*ymin + c*zmin-h < -eps1)
{ k++; continue; }
xmax = P.x + labmax*r1;
ymax = P.y + labmax*r2;
zmax = P.z + labmax*r3;
if (a*xmax + b*ymax + c*zmax-h < -eps1)
{ k++; continue; }
// If this test succeeds, an intersection of PQ and the pyramid
// lies in front of plane ABV.
// Test 6:
if (Poutside || hP < h-eps1)
{
T.x = xmin;
T.y = ymin;
linesegment(P, T, k+1);
}
if (Qoutside || hQ < h-eps1)
{
T.x = xmax;
T.y = ymax;
linesegment(Q, T, k+1);
}
worktodo = 0;
T.z = zmin;
T.z = zmax;
break;
}
if (worktodo)
{
fprintf(fout,"%f %f 0\n", P.x/P.z, P.y/P.z);
fprintf(fout,"%f %f 1\n", Q.x/Q.z, Q.y/Q.z);
}
}
Input file : a.dat
2.5 1 1
130
7 12
8 20 70
0500
1320
2300
3302
4200
5220
6020
123
203
021
458
859
569
9 6 10
8 9 10
7 13
7 14
01
13
30
12
23
45
11
7000
8202
8 10 11
6 7 10
56
59
9222
10 0 2 2
11 0 0 2
12 7 0 0
13 0 4 0
14 0 0 3
#
10 7 11
748
7 8 11
654
647
#
89
9 10
10 11
8 11
48
6 10
#
Output file : a.scratch
-0.528546 -0.483811 0
0.175470 -0.024754 1
-0.278002 -0.251895 1
0.383305 -0.050821 0
0.175470 -0.024754 1
0.131256 -0.105880 0
0.142799 0.126433 1
-0.091283 0.144565 0
-0.008598 0.284395 0
-0.008309 0.182602 1
-0.278002 -0.251895 0
0.101421 -0.160621 1
0.101421 -0.160621 0
-0.147350 0.118863 1
-0.147350 0.118863 0
0.142799 0.126433 1
0.142799 0.126433 0
0.188047 0.170387 1
0.188047 0.170387 0
-0.008309 0.182602 1
-0.091283 0.144565 0
-0.008309 0.182602 1
-0.278002 -0.251895 1
0.131256 -0.105880 0
0.040236 -0.091882 1
0.131256 -0.105880 0
-0.091283 0.144565 0
-0.088381 0.052613 1
0.175470 -0.024754 0
0.188047 0.170387 1
2. GENPLOT
// LeeGraph.h
#include <math.h>
#include "d_draw.h"
#include "d_linesh.h"
// openWindow(); viewWindow(); closeWindow();
// lineShape class
#include "d_textsh.h"
#define RD (0.0174533)
#define PI (3.141592)
#define ZERO 1.0E-20
#define BIG 1.e30
#define WS2VS_X(x)
// RD = 3.14159/180
(((x)-WS.x1)*mfx+VS.x1)
12
#define WS2VS_Y(y)
typedef float DEG;
((WS.y2-(y))*mfy+VS.y1)
struct POSI { float x, y, z ; int connect;};
#define MAX(a,b)
( (a)>(b)? (a): (b))
#define MIN(a,b)
( (a)<(b)? (a): (b))
#define MAX3(x,y,z) ((x)>(y)? MAX((x),(z)): MAX((y),(z)))
#define MIN3(x,y,z) ((x)<(y)? MIN((x),(z)): MIN((y),(z)))
#define TOGGLE(x) ((x)? FALSE : TRUE)
#define ABSVAL(val) ((val >= 0)? val: -val) /* Absolute Value Function */
#define RINGCHANGE(a,b,c) { a=b; b=c; c=a;}
#define SIGN(x)
((x) > 1e-5 ? 1: (x) < -1e-5 ? -1: 0)
#define SWAP(aux, a, b) { (aux) = (a); (a) = (b); (b) = (aux); }
#define SWAP3(aux,a,b,c) { (aux) = (a); (a) = (b); (b) = (c); (c) = (aux); }
struct WorkingSpace { float x1, y1, x2, y2; } WS;
struct ViewSpace {float x1, y1, x2, y2;} VS;
void
setWindow(float, float, float, float);
void DrawLine(POSI p1, POSI p2, shapeColor c);
void moveLength(POSI p1, POSI *p2, DEG a, float L);
void ShowViewCorner();
float mfx, mfy;
void setWindow(float x1, float y1, float x2, float y2)
{
bool isotropic=1;
WS.x1 = x1; WS.y1 = y1; WS.x2=x2; WS.y2=y2;
VS.x1 = 1; VS.y1 = 1; VS.x2=9; VS.y2=7;
openWindow();
ezdSetViewport(10,8);
mfx = (VS.x2-VS.x1)/(WS.x2-WS.x1);
mfy = (VS.y2-VS.y1)/(WS.y2-WS.y1);
if (isotropic) mfx = mfy = (mfx < mfy? mfx: mfy);
ShowViewCorner();
}
void moveLength(POSI p1, POSI *p2, DEG a, float L)
{
p2->x = p1.x + L*cos(a*RD);
p2->y = p1.y + L*sin(a*RD);
DrawLine(p1, *p2, black);
}
13
void DrawLine(POSI p1, POSI p2, shapeColor c)
{
POSI vp1, vp2;
vp1.x = WS2VS_X(p1.x); vp1.y = WS2VS_Y(p1.y);
vp2.x = WS2VS_X(p2.x); vp2.y = WS2VS_Y(p2.y);
lineShape Line(vp1.x, vp1.y, vp2.x, vp2.y, c);
Line.draw();
}
void ShowViewCorner()
{
float epx, epy; POSI P, Q;
epx = (VS.x2-VS.x1)*0.1; epy = epx*mfx/mfy;
// Show the four viewport corners:
P.x = Q.x = VS.x1; P.y = VS.y1; Q.y = VS.y1+epy;
lineShape Line1(P.x, P.y, Q.x, Q.y, red); Line1.draw();
P.x = VS.x1; Q.y = P.y = VS.y1; Q.x = VS.x1+epx;
lineShape Line2(P.x, P.y, Q.x, Q.y, red); Line2.draw();
P.x = VS.x2-epx; P.y = Q.y = VS.y1; Q.x = VS.x2;
lineShape Line3(P.x, P.y, Q.x, Q.y, red); Line3.draw();
P.x = Q.x = VS.x2; P.y = VS.y1; Q.y = VS.y1+epy;
lineShape Line4(P.x, P.y, Q.x, Q.y, red); Line4.draw();
P.x = Q.x = VS.x2; P.y = VS.y2-epy; Q.y = VS.y2;
lineShape Line5(P.x, P.y, Q.x, Q.y, red); Line5.draw();
P.x = VS.x2-epx; P.y = Q.y = VS.y2; Q.x = VS.x2;
lineShape Line6(P.x, P.y, Q.x, Q.y, red); Line6.draw();
P.x = VS.x1; P.y = Q.y = VS.y2; Q.x = VS.x1+epx;
lineShape Line7(P.x, P.y, Q.x, Q.y, red); Line7.draw();
P.x = Q.x = VS.x1; P.y = VS.y2-epy; Q.y = VS.y2;
lineShape Line8(P.x, P.y, Q.x, Q.y, red); Line8.draw();
}
// genplot.cpp : A General adjusting and plotting program
// The input is the file A.SCRATCH,
#include "LeeGraph.h"
void DetermineWS();
FILE *fp;
void main()
{
POSI P, Q;
14
DetermineWS();
setWindow(WS.x1, WS.y1, WS.x2, WS.y2);
fp = fopen("a.scratch", "r");
while(!feof(fp))
{
fscanf(fp,"%f %f %d\n",&Q.x,&Q.y,&Q.connect);
if (Q.connect) DrawLine(P,Q,black); P = Q;
}
fclose(fp);
viewWindow(); closeWindow();
}
void DetermineWS()
{
POSI Q;
fp = fopen("a.scratch", "r");
WS.x1 = WS.y1 = BIG;
WS.x2 = WS.y2 = -BIG;
while(!feof(fp))
{
fscanf(fp,"%f %f %d\n",&Q.x,&Q.y,&Q.connect);
WS.x1 = MIN(WS.x1, Q.x); WS.x2 = MAX(WS.x2, Q.x);
WS.y1 = MIN(WS.y1, Q.y); WS.y2 = MAX(WS.y2, Q.y);
}
fclose(fp);
}
3. 隱藏線處理 (完整)
// common.h
#include <stdio.h>
15
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include "d_draw.h"
#include "d_linesh.h"
// openWindow(); viewWindow(); closeWindow();
// lineShape class
#define MAX(x,y)
((x) > (y)? (x) : (y))
#define MIN(x,y)
((x) < (y)? (x) : (y))
#define MAX3(x,y,z) ((x)>(y)? MAX((x),(z)): MAX((y),(z)))
#define MIN3(x,y,z) ((x)<(y)? MIN((x),(z)): MIN((y),(z)))
#define SWAP(aux, a, b) { (aux) = (a); (a) = (b); (b) = (aux); }
#define SWAP3(aux,a,b,c) { (aux) = (a); (a) = (b); (b) = (c); (c) = (aux); }
#define SIGN(x)
((x) > eps ? 1: (x) < meps ? -1: 0)
#define RD (0.0174533) // RD = 3.14159/180
#define BIG 1.e30
typedef int INDEX;
typedef float COEF;
typedef float DEGREE;
struct POSI { float x, y, z; };
struct WorkSpace { float x1, y1, x2, y2; } WS;
struct ViewSpace {float x1, y1, x2, y2;} VS;
POSI Viewing(POSI P);
void Coeff();
DEGREE rho, theta, phi;
COEF v11, v12, v13, v21, v22, v23, v32, v33, v43;
/******************************************************************/
void Coeff()
//p.127
{
double th, ph, costh, sinth, cosph, sinph;
// angles in radians:
th = theta*RD; ph = phi*RD;
costh = cos(th); sinth = sin(th);
cosph = cos(ph); sinph = sin(ph);
// Elements of matrix V, see Eq. (4-9):
v11 = -sinth; v12 = -cosph*costh;
v13 = -sinph*costh;
16
v21 = costh;
v22 = -cosph * sinth; v23 = -sinph*sinth;
v32 = sinph;
v33= -cosph;
v43 = rho;
}
/******************************************************************/
POSI Viewing(POSI P)
// p.127
{
POSI T;
// Eye coordinates, computed as in Eq. (4-2):
T.x = v11*P.x + v21*P.y;
T.y = v12*P.x + v22*P.y + v32*P.z;
T.z = v13*P.x + v23*P.y + v33*P.z + v43;
return T;
}
// Hidlin.cpp
#include "common.h"
#define XWHOLE(x)
#define YWHOLE(y)
#define XREAL(i)
#define M -1000000.0
((int)(((x)-WS.x1)/deltaX))
((int)(((y)-WS.y1)/deltaY))
(WS.x1+((i))*deltaX)
#define NVERTEX 1200 // Max no of vertices
#define NTRIANGLE 800 // Max no of (no backface) triangles to be stored
#define NSCREEN 30
#define NPOLY 400 // Max no of vertices of a single polygon
#define NNTRSET 200 // Max size of set of triangles associated with
// a single (long) line segment
struct VERTEX { POSI p; int *connect; };
struct TRIANGLE { int A, B, C; float a, b, c, h; };
struct node { int jtr; struct node *next; } *pnode;
struct { int tr_cov; float tr_dist; struct node *start; }
SCREEN[NSCREEN][NSCREEN], *pointer;
int comment(char ch), reint(int *pi);
void rePosi(POSI *px);
void skipbl(), add_linesegment(int p1, int p2), error(char *str);
int counter_clock(int i0, int i1, int i2, float *pdist, int code);
void linesegment(POSI P,POSI Q,int k0);
void init_viewport(float, float,float,float);
void ScreenConst(), DrawSegment(), AddTria2Screen();
17
void ReadObjectStoreTriangle(), DividePolygon2Triangle(int npoly);
void ReadVertex(), InitialScreenMatrix(DEGREE a,DEGREE b,DEGREE c);
int
POLY[NPOLY], npoly, LOWER[NSCREEN],UPPER[NSCREEN], LOW[NSCREEN],
UP[NSCREEN], trset[NNTRSET], ntrset, ntr=0;
float mfx, mfy, deltaX, deltaY, slope, cx, cy;
const float eps=1e-5, meps=-1e-5, oneminus=1-1.e-5, oneplus=1+1.e-5;
VERTEX Vx[NVERTEX]; POSI Or; TRIANGLE TRI[NTRIANGLE];
FILE *fpin, *fout;
/******************************************************************/
void main()
// p.121
{
fpin = fopen("gen.in", "r"); fout = fopen("a.scratch","w");
if (fout == NULL) error("file a.scratch cannot be opened");
// Initialize screen matrix
InitialScreenMatrix(1000, 30, 60); // (rho, theta, phi)
Coeff();
openWindow();
init_viewport(0.5, 9.5, 0.5, 7.5);
// Read vertices
ReadVertex();
// Compute screen constants
ScreenConst();
// Read object faces and store triangles
ReadObjectStoreTriangle();
fclose(fpin);
// Add nearest triangles to screen lists:
AddTria2Screen();
// p.123
// Draw all line segments as far as they are visible
DrawSegment();
viewWindow(); closeWindow();
}
/******************************************************************/
void InitialScreenMatrix(DEGREE a,DEGREE b,DEGREE c) // p.121
{
INDEX ipix, jpix;
18
for (ipix = 0; ipix < NSCREEN; ipix++)
for (jpix = 0; jpix < NSCREEN; jpix++)
{
pointer = &(SCREEN[ipix][jpix]);
pointer->tr_cov = -1;
pointer->tr_dist = BIG;
pointer->start = NULL;
}
rePosi(&Or); rho = a; theta = b;
phi = c;
}
/******************************************************************/
void ReadVertex() //p.121
{
INDEX i; char ch; float X, Y;
POSI P, Pe; int
*ptr;
WS.x1 = WS.y1 = BIG; WS.x2 = WS.y2 = -BIG;
// Initialize vertex array
for (i = 0; i < NVERTEX; i++) Vx[i].connect=NULL;
while (skipbl(), ch=getc(fpin), ch != 'F' && ch != 'f')
{
ungetc(ch, fpin);
reint(&i);
rePosi(&P);
if (i < 0 || i >= NVERTEX) error("illegal vertex number");
P.x -= Or.x; P.y -= Or.y; P.z -= Or.z;
Pe = Viewing(P);
if (Pe.z <= eps)
{
printf("Object point O and vertex %d lie on ", i);
error("different sides of viewpoint E.");
}
X = Pe.x/Pe.z; Y = Pe.y/Pe.z;
WS.x1 = MIN(WS.x1, X); WS.x2 = MAX(WS.x2, X);
WS.y1 = MIN(WS.y1, Y); WS.y2 = MAX(WS.y2, Y);
Vx[i].p = Pe;
Vx[i].connect = ptr = new int;
if (ptr==NULL) error("memory allocation error 1");
*ptr = 0;
}
}
19
/******************************************************************/
void ScreenConst() // p. 121
{
float Xcentre, Ycentre, Xvp_centre, Yvp_centre;
float Xvp_range, Yvp_range, Xrange, Yrange;
Xrange = WS.x2-WS.x1;
Yrange = WS.y2 - WS.y1;
Xvp_range = VS.x2 - VS.x1;
Yvp_range = VS.y2 - VS.y1;
mfx = Xvp_range/Xrange;
mfy = Yvp_range/Yrange;
mfx = mfy = MIN(mfx,mfy);
Xcentre = 0.5*(WS.x1+WS.x2);
Ycentre = 0.5*(WS.y1+WS.y2);
Xvp_centre = 0.5*(VS.x1+VS.x2);
Yvp_centre = 0.5*(VS.y1+VS.y2);
cx = Xvp_centre - mfx*Xcentre;
cy = Yvp_centre - mfy*Ycentre;
deltaX = oneplus * Xrange/NSCREEN; deltaY = oneplus * Yrange/NSCREEN;
// Now we have: Xrange/deltaX < NSCREEN
}
/******************************************************************/
void ReadObjectStoreTriangle() // p.121-122
{
INDEX i, j;
int vertexnr, code;
float diag;
char ch;
while (!isspace(getc(fpin)));// The string "Faces: " has now been skipped
while (reint(&i) > 0)
{
POLY[0] = i; npoly = 1; skipbl();
while (ch=getc(fpin), ch != '#')
{
ungetc(ch, fpin); reint(&POLY[npoly++]);
if (npoly == NPOLY) error("too many vertices in one polygon");
}
if (npoly == 1) error("only one vertex of polygon");
if (npoly == 2)
{
add_linesegment(POLY[0], POLY[1]);
continue; }
if (!counter_clock(0, 1, 2, &diag, 0)) continue; //backface
for (i = 1; i <= npoly; i++)
{
j = i % npoly; code = POLY[j]; vertexnr = abs(code);
if (Vx[vertexnr].connect == NULL)
{
printf("vertex %d ", vertexnr);
error("undefined");
20
}
if (code <0) POLY[j] = vertexnr;
else add_linesegment(POLY[i-1], vertexnr);
}
// Division of a polygon into triangles, see section 3-5:
if (npoly > 2) DividePolygon2Triangle(npoly);
}
}
/******************************************************************/
void DividePolygon2Triangle(int npoly) // p.122
{
int i0, i1, i2, j, count=1, imin; float min_diag, diag;
while (npoly > 2)
{
min_diag = BIG;
for (i1 = 0; i1 < npoly; i1++)
{
i0 = (i1 == 0 ? npoly-1: i1-1);
i2 = (i1 == npoly-1 ? 0 : i1+1);
if (counter_clock(i0, i1, i2, &diag, 0) && diag < min_diag)
{
min_diag = diag; imin = i1;
}
}
i1 = imin;
i0 = (i1 == 0 ? npoly-1 : i1-1);
i2 = (i1 == npoly-1 ? 0 : i1+1);
// store triangle in array TRI and in screen lists:
counter_clock(i0, i1, i2, &diag, count++);
npoly --;
for (j = i1; j <= npoly; j++) POLY[j] = POLY[j+1];
}
}
/******************************************************************/
void AddTria2Screen()
//p.122
{
INDEX ipix, jpix;
for (ipix = 0; ipix < NSCREEN; ipix++)
for (jpix = 0; jpix < NSCREEN; jpix++)
{
pointer = &(SCREEN[ipix][jpix]);
if ((*pointer).tr_cov >= 0)
{
21
pnode = new (struct node);
if (pnode == NULL) error("memory allocation error 2");
pnode->jtr = pointer->tr_cov;
pnode->next = pointer->start;
pointer->start = pnode;
}
}
}
/******************************************************************/
void DrawSegment()
//p.123
{
INDEX p, q, iconnect, ipix, jpix, ipixleft, ipixright;
int *ptr, trnr, jtr, jtop, jbot, j; POSI P, Q;
float xP, yP, xQ, yQ, xLft, xRght, yLft, yRght, denom;
// Draw all line segments as far as they are visible
for (p = 0; p < NVERTEX; p++)
{
ptr = Vx[p].connect; if (ptr == NULL) continue;
P = Vx[p].p; xP = P.x/P.z; yP = P.y/P.z;
for (iconnect = 1; iconnect <= *ptr; iconnect ++)
{
q = *(ptr+iconnect);
Q = Vx[q].p;
xQ = Q.x/Q.z; yQ = Q.y/Q.z;
// Using the screen lists, we shall build the set of
// triangles that may hide points of PQ:
if (xP < xQ || (xP == xQ && yP < yQ))
{
xLft = xP; yLft = yP; xRght = xQ; yRght = yQ; }
else {xLft = xQ; yLft = yQ; xRght = xP; yRght = yP;}
ipixleft = XWHOLE(xLft); ipixright = XWHOLE(xRght);
denom = xRght - xLft;
if (fabs(denom) <= eps)
denom = eps;
slope = (yRght-yLft)/denom;
jbot = jtop = YWHOLE(yLft);
for (ipix = ipixleft; ipix <= ipixright; ipix++)
{
j = (ipix==ipixright ? YWHOLE(yRght):
YWHOLE(yLft+(XREAL(ipix+1)-xLft)*slope));
LOWER[ipix] = MIN(jbot, j); jbot = j;
UPPER[ipix] = MAX(jtop, j); jtop = j;
22
}
ntrset = 0;
for (ipix = ipixleft; ipix <= ipixright; ipix++)
for (jpix = LOWER[ipix]; jpix <= UPPER[ipix]; jpix++)
{
pointer = &(SCREEN[ipix][jpix]);
pnode = pointer->start;
while(pnode != NULL)
{
trnr = pnode->jtr; // trnr will be store only if it is not yet
// present in array trset (the triangle set)
trset[ntrset] = trnr; //sentinel
jtr = 0;
while (trset[jtr] != trnr) jtr++;
if (jtr == ntrset)
{
ntrset ++; // this means that trnr is stored
if (ntrset == NNTRSET) error("triangle set overflow\n");
}
pnode = pnode->next;
}
}
// Now trset[0],..., trset[ntrset-1] is the set of triangles that may hide points of PQ
linesegment(P, Q, 0);
}
}
}
/******************************************************************/
void skipbl() //p.124
{
char ch;
do ch = getc(fpin); while(isspace(ch) || comment(ch));
ungetc(ch, fpin);
}
/******************************************************************/
int comment(char ch) //p.124
{
int k;
23
if (ch == '(')
{
do k = getc(fpin);
return k==')';
while(k != ')' && k != EOF);
}
else return 0;
}
/******************************************************************/
void rePosi(POSI *p)
//p.124
{
skipbl(); fscanf(fpin, "%f %f %f", &(p->x), &(p->y), &(p->z));
}
/******************************************************************/
int reint(int *p)
//p.124
{
skipbl(); return fscanf(fpin, "%d", p);
}
/******************************************************************/
void add_linesegment(int p1, int p2) // p.124
{
INDEX i; int iaux, *ptr, n;
if (p1 > p2) SWAP(iaux, p1, p2);
// Now: p1 < p2
ptr = Vx[p1].connect; n = *ptr;
for (i = 1; i <= n; i++)
if (*(ptr+i) == p2) return; // p2 already in list
n++;
Vx[p1].connect = ptr = (int*)realloc(ptr,(n+1)*sizeof(int));
if (ptr == NULL) error("memory allocation error 3");
*(ptr+n) = p2; *ptr = n;
}
/******************************************************************/
int counter_clock(int i0, int i1, int i2, float *pdist, int code) //p.124-126
// code = 0: compute orientation; if counter-clockwise,
//
compute length of projected diagonal AC
// code = 1: compute a, b, c, h; store the first triangle
24
// code > 1: check if next triangle is coplanar; store it
{
INDEX ipix, jpix, ipixmin, ipixmax, ipixleft, ipixright, i;
int j_old, j;
int A=abs(POLY[i0]), B=abs(POLY[i1]), C=abs(POLY[i2]), topcode[3];
float r, xdist, ydist, zdist, xA, yA, xB, yB, xC, yC, h0;
float DA, DB, DC, D, DAB, DAC, DBC, aux, dist, xR, yR;
float Xleft[3], Xright[3], Yleft[3], Yright[3];
static float a, b, c, h;
POSI PA, PB, PC;
float denom;
PA = Vx[A].p;
PB = Vx[B].p;
PC = Vx[C].p;
// p. 125
h0 = PA.x*(PB.y*PC.z-PC.y*PB.z) - PB.x*(PA.y*PC.z-PC.y*PA.z) +
PC.x*(PA.y*PB.z-PB.y*PA.z);
if (code == 0)
{
if(h0 > eps)
{
xdist = PC.x-PA.x; ydist = PC.y-PA.y;
zdist = PC.z-PA.z;
*pdist = xdist*xdist + ydist*ydist + zdist*zdist;
return 1;
}
else return 0;
}
// If h0 = 0, plane ABC passes through E and hides nothing.
// If h0 < 0, triangle ABC is a backface.
// In both cases ntr is not incremented and the triangles
// of the polygon are not stored
if (code == 1)
//p.125
{
a = PA.y*(PB.z-PC.z) - PB.y*(PA.z-PC.z) + PC.y*(PA.z-PB.z);
b = -(PA.x*(PB.z-PC.z) - PB.x*(PA.z-PC.z) + PC.x*(PA.z-PB.z));
c = PA.x*(PB.y-PC.y) - PB.x*(PA.y-PC.y) + PC.x*(PA.y-PB.y);
r = sqrt(a*a + b*b + c*c);
if(r == 0.0) r = eps;
a /= r; b /= r; c /= r; h = h0/r;
}
else if (fabs(a*PC.x+b*PC.y+c*PC.z-h) > 0.001*fabs(h))
{
25
printf("Polygon containing vertices %d %d %d ", A, B, C);
error(" incorrectly specified");
}
if (ntr == NTRIANGLE)
error("Too many triangles");
TRI[ntr].A = A; TRI[ntr].B = B; TRI[ntr].C = C;
TRI[ntr].a = a; TRI[ntr].b = b; TRI[ntr].c = c;
TRI[ntr].h = h;
// The triangle will now be stored in the screen lists of the associated
// pivels; first the arrays LOWER, UPPER, LOW, UP are defined:
xA = PA.x/PA.z; yA = PA.y/PA.z; xB = PB.x/PB.z; yB = PB.y/PB.z;
xC = PC.x/PC.z; yC = PC.y/PC.z;
DA = xB*yC - xC*yB;
DB = xC*yA - xA*yC;
DC = xA*yB - xB*yA;
D = DA+DB+DC;
DAB = DC - M*(xA-xB); DAC = DB - M*(xC-xA); DBC = DA - M*(xB-xC);
topcode[0] = (D*DAB>0); topcode[1] = (D*DAC>0);
topcode[2] = (D*DBC>0);
Xleft[0] = xA; Yleft[0] = yA; Xright[0] = xB; Yright[0] = yB;
Xleft[1] = xA; Yleft[1] = yA; Xright[1] = xC; Yright[1] = yC;
Xleft[2] = xB; Yleft[2] = yB; Xright[2] = xC; Yright[2] = yC;
for (i = 0; i < 3; i++) // i=triangle-side number
if(Xleft[i] > Xright[i] ||
(Xleft[i] == Xright[i] && Yleft[i] > Yright[i]))
{
SWAP(aux, Xleft[i], Xright[i]);
SWAP(aux, Yleft[i], Yright[i]);
}
ipixmin = XWHOLE(MIN3(xA,xB,xC)); ipixmax = XWHOLE(MAX3(xA,xB,xC));
for (ipix = ipixmin; ipix <= ipixmax; ipix++)
{
LOWER[ipix] = UP[ipix] = 100000;
UPPER[ipix] = LOW[ipix]=-100000;
}
for (i = 0; i < 3; i++) //p.126
{
ipixleft = XWHOLE(Xleft[i]);
ipixright = XWHOLE(Xright[i]);
denom = Xright[i]-Xleft[i];
if (denom == 0.) denom = 1.0e-10;
26
slope = (Yright[i]-Yleft[i])/denom;
j_old = YWHOLE(Yleft[i]);
for (ipix = ipixleft; ipix <= ipixright; ipix++)
{
j = (ipix == ipixright ? YWHOLE(Yright[i]) :
YWHOLE(Yleft[i]+(XREAL(ipix+1)-Xleft[i])*slope));
if(topcode[i])
{
UPPER[ipix] = MAX3(j_old, j, UPPER[ipix]);
UP[ipix] = MIN3(j_old, j, UP[ipix]);
}
else
{
LOWER[ipix] = MIN3(j_old, j, LOWER[ipix]);
LOW[ipix] = MAX3(j_old, j, LOW[ipix]);
}
j_old = j;
}
}
// For screen column ipix, the triangle is associated only with pixels
// in the rows LOWER[ipix],...,UP[ipix]-1 of these rows denote pixels
// that lie completely whithin the triangle.
for (ipix = ipixmin; ipix <= ipixmax; ipix++)
for (jpix = LOWER[ipix]; jpix <= UPPER[ipix]; jpix++)
{
pointer = &(SCREEN[ipix][jpix]);
if (jpix > LOW[ipix] && jpix < UP[ipix])
{
xR = WS.x1 + (ipix+0.5)*deltaX;
yR = WS.y1 + (jpix+0.5)*deltaY;
denom = a*xR + b*yR + c*mfx;
if(fabs(denom) <= eps) denom = eps;
dist = h*sqrt(xR*xR + yR*yR + 1)/denom;
// This line from viewpoint E to pixel point (xR, yR, 1)
// intersects plane ABC at a distance dist from E.
if(dist < pointer->tr_dist)
{ pointer->tr_cov = ntr; pointer->tr_dist = dist;}
}
27
else // Add triangle to screen list:
{
pnode = new (struct node);
if (pnode == NULL) error("memory allocation error 4");
pnode->jtr = ntr;
pnode->next = pointer->start;
pointer->start = pnode;
}
}
ntr++;
}
/******************************************************************/
void error(char *str) { printf("%s\n",*str); exit(1); } //p.126
/******************************************************************/
void linesegment(POSI P, POSI Q, int k0) //p.127
{
// line segment PQ is to be drawn, as far as it is not hidden by the
// triangles trset[k0] to trset[ntrset-1].
bool worktodo = 1, Pbeyond, Qbeyond, outside, Poutside, Qoutside;
INDEX i, j, k=k0; int ia, ib, ic, sum;
POSI T, A, B, C;
float a, b, c, h, hP, hQ, r1, r2, r3, dA, dB, dC, labmin, labmax, lab,
mu, xmin, ymin, zmin, xmax, ymax, zmax, c1, c2, c3, k1, k2, k3,
denom1, denom2, Cpos, Ppos, Qpos, aux, eps1;
while (k < ntrset)
{
j = trset[k];
a = TRI[j].a;
b = TRI[j].b;
c = TRI[j].c; h = TRI[j].h;
// Test 1:
hP = a*P.x + b*P.y + c*P.z; hQ = a*Q.x + b*Q.y + c*Q.z;
eps1 = eps +eps*h;
if (hP-h <= eps1 && hQ-h <= eps1)
{
k++; continue; }
// PQ not behind ABC
// Test 2:
k1 = P.y*Q.z - Q.y*P.z; k2 = P.z*Q.x - Q.z*P.x; k3 = P.x*Q.y - Q.x*P.y;
ia = TRI[j].A; ib = TRI[j].B; ic = TRI[j].C;
A = Vx[ia].p;
B = Vx[ib].p;
C = Vx[ic].p;
28
dA = k1*A.x + k2*A.y + k3*A.z; dB = k1*B.x + k2*B.y + k3*B.z;
dC = k1*C.x + k2*C.y + k3*C.z;
// p.128
// If dA, dB, dC have the same sign, the vertices ia, ib, ic
// lie at the same side of plane EPQ.
sum = SIGN(dA) + SIGN(dB) + SIGN(dC);
if (abs(sum) >= 2) { k++; continue; }
// If this test succeeds, the (infinite) line PQ lies outside
// pyramid EABC (or the line and the pyramid have at most one
// point in common). If the test fails, there is a point of
// intersection.
// Test 3:
Poutside = Qoutside = 0; labmin = 1.; labmax = 0.;
for (i = 0; i < 3; i++)
{
c1 = A.y*B.z-B.y*A.z; c2 = A.z*B.x-B.z*A.x; c3 = A.x*B.y-B.x*A.y;
// c1 x + c2 y + c3 z = 0 is plane EAB
Cpos = c1*C.x + c2*C.y + c3*C.z;
Ppos = c1*P.x + c2*P.y + c3*P.z;
Qpos = c1*Q.x + c2*Q.y + c3*Q.z;
denom1 = Qpos - Ppos;
if (Cpos > eps)
{
Pbeyond = Ppos < meps; Qbeyond = Qpos < meps;
outside = (Pbeyond && Qpos <= eps) || (Qbeyond && Ppos <= eps);
}
else if (Cpos < meps)
{
Pbeyond = Ppos > eps; Qbeyond = Qpos > eps;
outside = (Pbeyond && Qpos>= meps) || (Qbeyond && Ppos >= meps);
}
else outside = 1;
if (outside) break;
lab = (fabs(denom1)<=eps ? 1.e7 : -Ppos/denom1);
// lab indicates where PQ meets plane EAB
Poutside |= Pbeyond;
Qoutside |= Qbeyond;
denom2 = dB-dA;
mu = (fabs(denom2)<=eps ? 1.e7 : -dA/denom2);
29
// mu tells where AB meets plane EPQ
if (mu >= meps && mu <= oneplus && lab >= meps && lab <= oneplus)
{ labmin = MIN(lab, labmin); labmax = MAX(lab, labmax); }
SWAP3(T, A, B, C);
SWAP3(aux, dA, dB, dC);
}
if (outside) { k++; continue; }
// Test 4:
if (!(Poutside || Qoutside)) {worktodo = 0; break; }// PQ invisible
// p.129
Test 5:
r1 = Q.x-P.x; r2 = Q.y-P.y; r3 = Q.z-P.z;
xmin = P.x+labmin*r1; ymin = P.y+labmin*r2; zmin = P.z+labmin*r3;
if (a*xmin+b*ymin+c*zmin-h < -eps1)
{ k++; continue; }
xmax = P.x+labmax*r1; ymax = P.y+labmax*r2; zmax = P.z+labmax*r3;
if (a*xmax+b*ymax+c*zmax-h < -eps1)
{ k++; continue; }
// If this test succeeds, an intersection of PQ and the pyramid
// lies in front of plane ABV.
// Test 6:
if (Poutside || hP < h-eps1)
{
T.x = xmin; T.y = ymin; T.z = zmin;
linesegment(P, T, k+1);
}
if (Qoutside || hQ < h-eps1)
{
T.x = xmax; T.y = ymax; T.z = zmax;
linesegment(Q, T, k+1);
}
worktodo = 0;
break;
}
if (worktodo)
{
lineShape Line(mfx*P.x/P.z+cx, 8-mfy*P.y/P.z-cy,
mfx*Q.x/Q.z+cx, 8-mfy*Q.y/Q.z-cy, black);
Line.draw();
fprintf(fout,"%f %f 0\n",P.x/P.z, P.y/P.z);
fprintf(fout,"%f %f 1\n",Q.x/Q.z, Q.y/Q.z);
}
30
}
/******************************************************************/
void init_viewport(float x1, float x2, float y1, float y2)
{
float len = 0.2;
VS.x1 = x1; VS.x2 = x2; VS.y1 = y1; VS.y2 = y2;
// Show the four viewport corners:
lineShape Line1(x1, y1, x1, y1+len, red);
Line1.draw();
lineShape Line2(x1, y1, x1+len, y1, red);
Line2.draw();
lineShape Line3(x2-len, y1, x2, y1, red);
Line3.draw();
lineShape Line4(x2, y1, x2, y1+len, red);
lineShape Line5(x2, y2-len, x2, y2, red);
lineShape Line6(x2-len, y2, x2, y2, red);
lineShape Line7(x1, y2, x1+len, y2, red);
lineShape Line8(x1, y2-len, x1, y2, red);
ezdDrawPoint((x1+x2)/2, y1);
Line4.draw();
Line5.draw();
Line6.draw();
Line7.draw();
Line8.draw();
}
/******************************************************************/
// a.dat
0
0 30
0
0 -30 0
10 -10 -30 0
1
0 -20 0
11 -10 -20 0
2 0 -16 8
12 -10 -16 8
3 0 16 8
13 -10 16 8
4 0 20 0
14 -10 20 0
5 0 30 0
15 -10 30 0
6 0 0 60
16 -10 0 60
7 0 -12 16
17 -10 -12 16
8 0 12 16
18 -10 12 16
9 0 0 40
31
19 -10
Faces:
0 40
0 1 2 3 4 5 6 -9 8 7 9 -6#
10 16 -19 17 18 19 -16 15 14 13 12 11#
1 11 12 2#
2 12 13 3#
14 4
3 13#
7 8 18 17#
7 17 19 9#
18 8 9 19#
5 15 16 6#
10 0
10 11
14 15
6 16#
1 0#
5 4#
// rho = 70, theta = 20, phi = 80
5. 例 1:Lettersa
// lettersa.cpp:
A preprocessor for Hidlin.cpp
#include <stdio.h>
#define thickness 10
#define s(p) ( (p) >= 0 ? (p)+base : (p) - base)
typedef struct Point3Struct {float x, y, z; } Point3;
#define point(i,P) fprintf(fp, "%d %f %f %f\n",i,P.x,P.y,P.z)
#define face4(a,b,c,d) fprintf(fp,"%4d %4d %4d %4d#\n",s(a),s(b),s(c),s(d))
#define face12(a,b,c,d,e,f,g,h,i,j,k,l) \
fprintf(fp, "%4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d#\n",\
32
s(a), s(b), s(c), s(d), s(e), s(f), s(g), s(h), s(i), \
s(j), s(k), s(l))
int base;
FILE *fp;
void main()
{
int n, i, j, nr;
static Point3 Q, P[20]=
{ {0, -30, 0}, {0, -20, 0} , {0, -16, 8}, {0, 16, 8}, {0, 20, 0},
{ 0, 30, 0}, {0, 0, 60}, {0, -12, 16}, {0, 12, 16}, {0, 0, 40}};
printf("How many letters?\n");
scanf("%d",&n);
fp = fopen("a.dat","w");
fprintf(fp,"%f %f %f\n", -(n-0.5)*thickness, 0.0, 30.0);
for (j = 10; j < 20; j++)
{
P[j].x=-thickness; P[j].y = P[j-10].y; P[j].z = P[j-10].z;
for (i = 0; i < n; i++)
for (j = 0; j < 20; j++)
{
nr = 20*i+j;
Q = P[j];
Q.x = P[j].x-2*i*thickness;
point(nr,Q);
}
fprintf(fp,"Faces:\n");
for (i = 0; i < n; i++)
{
base = 20*i;
face12( 0, 1, 2, 3, 4, 5, 6, -9, 8, 7, 9, -6);
face12(10, 16, -19, 17, 18, 19, -16, 15, 14, 13, 12, 11);
face4( 1, 11, 12, 2);
face4( 2, 12, 13, 3);
face4(14, 4, 3, 13);
face4( 7, 8, 18, 17);
face4( 7, 17, 19, 9);
face4( 5, 15, 16, 6);
face4(10, 11, 1, 0);
face4(18, 8, 9, 19);
face4(10, 0, 6, 16);
face4(14, 15, 5, 4);
}
fclose(fp);
}
// rho = 700, theta = 80, phi = 80
33
}
6. 例 2:
//hollow.cpp: A preprocessor for Hidlin.cpp
#include <stdio.h>
#include <math.h>
#define PI (3.14159)
void main()
{
FILE *fp;
int i, j, k, l, m, n;
float r, R, alpha, cosa, sina, delta, h, radius, hite;
printf("Give number n (n points on a circle):"); scanf("%d", &n);
printf("Give cylinder height:");
scanf("%f",&h);
printf("Give large radius R and small r:\n"); scanf("%f %f", &R, &r);
fp = fopen("cyl.dat", "w");
delta = 2.0*PI/n;
fprintf(fp,"0.0 0.0 %7.2f\n", 0.5*h);
for (i=1; i <= n; i++)
{
alpha = i*delta; cosa = cos(alpha); sina = sin(alpha);
for (l = 0; l < 2; l++) // l=0: outer, l=1: inner circle
{
radius = (l == 0 ? R : r);
for (m = 0; m < 2; m++) // m=0: top, m=1: bottom boundary
{
34
k = i + l*n + m*2*n;
hite = (m==0? h : 0);
fprintf(fp,"%d %9.5f %9.5f %9.5f\n",
k, radius*cosa, radius*sina, hite);
}
}
}
fprintf(fp, "Faces:\n");
// Top boundary face:
for (i=1; i<=n; i++) fprintf(fp,"%d ",i);
fprintf(fp,"%d\n", -2*n);
for(i=2*n-1; i>=n+1;i--) fprintf(fp, "%d ",i);
fprintf(fp,"%d %d#\n", 2*n, -n);
// Bottom boundary face:
fprintf(fp, "%d %d\n", 3*n, -4*n);
for (i=3*n+1; i<=4*n; i++) fprintf(fp,"%d ",i);
fprintf(fp,"%d\n",-3*n);
for (i=3*n-1; i >= 2*n+2; i--) fprintf(fp,"%d ",i);
fprintf(fp,"%d#\n", 2*n+1);
// Vertical lines:
for (i = 1; i <= n; i++)
{
j=i%n+1;
fprintf(fp, "%d %d %d %d#\n",j,i,i+2*n,j+2*n);
fprintf(fp, "%d %d %d %d#\n",i+n, j+n, j+3*n, i+3*n);
}
fclose(fp);
}
N = 10, h=10, R=30, r=25
// rho = 1700, theta = 20, phi = 60
35
N = 100, h=10, R=30, r=25
// rho = 1700, theta = 20, phi = 60
7. 例 3
//beams.cpp: A preprocessor for Hidlin.cpp
#include <stdio.h>
#define point(i,P) fprintf(fp, "%d %f %f %f\n",i,P.x,P.y,P.z)
#define face4(a,b,c,d) fprintf(fp,"%d %d %d %d#\n",a,b,c,d)
void main()
{
struct POSI {float x, y, z;} A, B, C, D; FILE *fp;
int i, j, n, k; float l, w, a, b, aux;
printf("How many beams?\n"); scanf("%d", &n);
printf("The beam measures l x w x w. \nGive l and w: ");
scanf("%f %f",&l, &w);
fp = fopen("beams.dat", "w");
fprintf(fp, "0.0 0.0 %f\n", 0.5*n*w); // central object point
36
a = 0.5*l;
b = a-w;
A.x = a; A.y = -a; B.x = a; B.y = a; C.x = b; C.y = a; D.x = b; D.y = -a;
for(i = 0; i < n; i++)
{
for(j = 0; j < 2; j++)
{
A.z = B.z = C.z = D.z = (i+j)*w; k = 8*i + 4*j;
point(k, A);
point(k+1, B);
point(k+2, C);
point(k+3, D);
}
aux = A.x; A.x = -A.y; A.y = aux;
aux = B.x; B.x = -B.y; B.y = aux;
aux = C.x; C.x = -C.y; C.y = aux;
aux = D.x, D.x = -D.y; D.y = aux;
}
fprintf(fp, "Faces:\n");
for (i = 0; i < n; i++)
{
k = 8*i;
face4(k, k+3, k+2, k+1); // bottom
face4(k+4, k+5, k+6, k+7); // top
face4(k, k+1, k+5, k+4);
face4(k+3, k+7, k+6, k+2);
face4(k, k+4, k+7, k+3);
face4(k+1, k+2, k+6, k+5);
// front
// bkck
// left
// right
}
fclose(fp);
}
37
8. 例 4
//staircase.cpp: A preprocessor for Hidlin.cpp
#include <stdio.h>
#include <math.h>
#define PI (3.14159)
#define point(i,P) fprintf(fp, "%d %f %f %f\n",i,P.x,P.y,P.z)
#define face4(a,b,c,d) fprintf(fp,"%d %d %d %d#\n",a,b,c,d)
void main()
{
FILE *fp;
int i, j, k, l, m, n;
float r, R, alpha, cosa, sina, delta, h, H;
struct POSI {float x, y, z;} A, P[10];
printf("Give number n (n points on a stairs):"); scanf("%d", &n);
printf("Give height of a single stair step:");
scanf("%f",&h);
printf("Give large radius R and small r:\n"); scanf("%f %f", &R, &r);
fp = fopen("winding.dat", "w");
delta = 2.0*PI/n;
fprintf(fp,"0.0 0.0 %7.2f\n", 0.5*n*h);
for (j=0; j<4; j++) P[j].z = 0;
for (j=4; j<8; j++) P[j].z = h/5;
P[0].x = P[1].x = P[4].x = P[5].x = R;
P[2].x = P[3].x = P[6].x = P[7].x = r;
P[0].y = P[4].y = P[3].y = P[7].y = -0.75*h;
38
P[1].y = P[5].y = P[2].y = P[6].y = 0.75*h;
P[8].x = R; P[8].y = 0; P[8].z = h/10;
P[9].x = R; P[9].y = 0; P[9].z = 5*h;
m = 10*n; H = n*h;
for (i = 0; i < n; i++)
{
alpha = i*delta; cosa = cos(alpha); sina = sin(alpha);
for (j=0; j<10; j++)
{
k = 10*i+j;
A.x = P[j].x*cosa - P[j].y*sina; A.y = P[j].x*sina + P[j].y*cosa;
A.z = P[j].z + i*h;
point(k, A);
}
A.x = r*cosa; A.y = r*sina; A.z = 0.0;
point(m+i, A);
A.z = H+5*h;
point(m+n+i, A);
}
fprintf(fp, "Faces:\n");
for (i = 0; i < n; i++)
{
k = 10*i;
face4(k , k+1, k+5, k+4);
face4(k+2, k+3, k+7, k+6);
face4(k+1, k+2, k+6, k+5);
face4(k+3, k , k+4, k+7);
face4(k+4, k+5, k+6, k+7);
face4(k+1, k, k+3, k+2);
fprintf(fp, "%d %d#\n", k+8, k+9);
if (i < n-1) fprintf(fp, "%d %d#\n",k+9, k+19);
}
for (i=0; i<n; i++)
for (l=0; l<2; l++)
face4(m+i, m+(i+1)%n, m+n+(i+1)%n, m+n+i);
{
for (i=0; i<n; i++) fprintf(fp, " %d", m+l*n+i);
fprintf(fp,"#\n");
}
fclose(fp);
}
39
9. 例 5
//torus.cpp:
A preprocessor for Hidlin.cpp
#include <stdio.h>
#include <math.h>
#define PI (3.14159)
void main()
{
FILE *fp;
int i, j, n;
float r, R, alpha, beta, cosa, sina, delta, x, x1, y1, z1;
printf("Give number n (to draw an n x n torus):"); scanf("%d", &n);
printf("Give large radius R and small r:\n"); scanf("%f %f", &R, &r);
fp = fopen("torus.dat", "w");
delta = 2.0*PI/n;
fprintf(fp,"0.0 0.0 0.0\n"); // central object point
for (i=0; i<n; i++)
{
alpha = i*delta; cosa = cos(alpha); sina = sin(alpha);
for (j=0; j<n; j++)
{
beta = j*delta;
x = R + r*cos(beta); // y=0
x1 = x*cosa; y1 = x*sina; z1 = r*sin(beta); //z1 = z;
fprintf(fp, "%d %f %f %f\n", i*n+j, x1, y1, z1);
}
40
}
fprintf(fp, "Faces:\n");
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
fprintf(fp, "%d %d %d %d#\n",i*n+j,(i+1)%n*n+j,
(i+1)%n*n+(j+1)%n, i*n+(j+1)%n);
fclose(fp);
}
10. 例 6
//sphere.cpp:
A preprocessor for Hidlin.cpp
#include <stdio.h>
#include <math.h>
#define PI (3.14159)
void main()
{
FILE *fp;
int i, j, n, A, B, C, D, P, Q;
float alpha, beta, delta, cosa, sina, cosb, sinb;
printf("Give number n (to draw an n x n semi-sphere):"); scanf("%d", &n);
fp = fopen("semi.dat", "w");
delta = 0.5*PI/n;
fprintf(fp,"0.0 0.0 -0.5\n"); // central object point
// R = 1; sphere centre in 0
41
fprintf(fp,"0 0.0 0.0 -1.0\n"); // first point
for (i=0; i<4*n; i++)
{
alpha = i*delta; cosa = cos(alpha); sina = sin(alpha);
for (j=1; j<=n; j++)
{
beta = j*delta;
cosb = cos(beta); sinb = sin(beta);
fprintf(fp, "%d %f %f %f\n", i*n+j, sinb*cosa, sinb*sina, -cosb);
}
}
fprintf(fp, "Faces:\n");
for (i = 0; i < 4*n; i++)
{
P=i*n+1; Q=(i+1)%(4*n)*n+1;
fprintf(fp,"%d %d %d#\n",0, P, Q);
fprintf(fp,"%d %d %d#\n",0, Q, P);
for (j = 1; j < n; j++)
{
A=P+j-1; B=Q+j-1; C=Q+j; D=P+j;
fprintf(fp, "%d %d %d %d#\n",A,B,C,D);
fprintf(fp, "%d %d %d %d#\n",D,C,B,A);
}
}
fclose(fp);
}
x2+y2+z2=1,
-1<=z<=0
42
11. 例 7
//function.cpp:
A preprocessor for Hidlin.cpp
#include <stdio.h>
typedef float COEFF;
#define point(i,x,y,z) fprintf(fp, "%d %f %f %f\n",i,x,y,z)
#define face3(a,b,c) fprintf(fp,"%d %d %d#\n",a,b,c)
#define line(a,b) fprintf(fp,"%d %d#\n",a,b)
float f(float x, float y);
void InputPolynomial();
void SetRange(), SetGrid(), OutputData();
FILE *fp= fopen("func.dat", "w");
COEFF a, b, c, d, e, g;
float xmin, xmax, ymin, ymax, hx, hy, x, y, zc, xaxis, yaxis, zaxis;
int Nx, Ny;
void main()
{
InputPolynomial();
SetRange();
SetGrid();
OutputData();
fclose(fp);
}
float f(float x, float y)
{ return a*x*x+b*y*y+c*x*y+d*x+e*y+g;}
void InputPolynomial()
{
printf("f(x,y)=a.x.x + b.y.y + c.x.y + d.x + e.y +g\n");
printf("a, b, c, d, e, g: ");
scanf("%f %f %f %f %f %f", &a, &b, &c, &d, &e, &g);
}
void SetRange()
{
printf("xmin, xmax, ymin, ymax: ");
scanf("%f %f %f %f",&xmin, &xmax, &ymin, &ymax);
printf("Central z-value: "); scanf("%f",&zc);
printf("Length of positive axes to be drawn (x,y,z): ");
43
scanf("%f %f %f", &xaxis, &yaxis, &zaxis);
x = (xmin+xmax)/2; y=(ymin+ymax)/2;
}
void SetGrid()
{
printf("Nx, Ny: ");
scanf("%d %d", &Nx, &Ny);
hx = (xmax-xmin)/Nx; hy = (ymax-ymin)/Ny;
}
void OutputData()
{
int i, j, k, l;
fprintf(fp, "%f %f %f\n", x,y,zc);
for(i=0; i<=Nx; i++)
for(j=0; j<=Ny; j++)
{
x = xmin + i*hx; y = ymin + j*hy;
point(j*(Nx+1)+i+1, x, y, f(x,y));
}
k = (Nx+1)*(Ny+1);
point(++k, 0.0, 0.0, 0.0);
point(++k, xaxis, 0.0, 0.0);
point(++k, 0.0, yaxis, 0.0); point(++k, 0.0, 0.0, zaxis);
fprintf(fp,"Faces:\n");
for(i = 0; i < Nx; i++)
for(j = 0; j < Ny; j++)
{
k=j*(Nx+1)+i+1; l = k+Nx+1;
face3(k, -(l+1), k+1);
face3(k+1, l+1, -k);
face3(k, -(l+1), l);
face3(l, l+1, -k);
}
k = (Nx+1)*(Ny+1);
line(k+1, k+2); // x-axis
line(k+1, k+3); // y-axis
line(k+1, k+4); // z-axis
}
F(x, y) = 0.1x2-0.4y2
-5 ≦ x ≦ 5, -2 ≦ y ≦ 2 Nx = 20, Ny=8, zc = 0, (x,y,z): (5, 5, 5)
rho = 20, theta = 50, phi = 80
44
12. 例 8
//fun2.cpp: A preprocessor for Hidlin.cpp
#include <stdio.h>
#include <math.h>
float f(float x, float y);
void InputPolynomial();
void SetRange();
void SetGrid();
void OutputData();
FILE *fp= fopen("func.dat", "w");
float xmin, xmax, ymin, ymax, hx, hy, x, y, zc, xaxis, yaxis, zaxis;
int Nx, Ny;
void main()
{
SetRange();
SetGrid();
OutputData();
fclose(fp);
}
float f(float x, float y)
{
45
float RD = 0.0174533;
return (70*cos(sqrt(x*x+y*y)*RD));
}
void SetRange()
{
printf("xmin, xmax, ymin, ymax: ");
scanf("%f %f %f %f",&xmin, &xmax, &ymin, &ymax);
printf("Central z-value: "); scanf("%f",&zc);
printf("Length of positive axes to be drawn (x,y,z): ");
scanf("%f %f %f", &xaxis, &yaxis, &zaxis);
x = (xmin+xmax)/2;
y=(ymin+ymax)/2;
}
void SetGrid()
{
printf("Nx, Ny: ");
scanf("%d %d", &Nx, &Ny);
hx = (xmax-xmin)/Nx; hy = (ymax-ymin)/Ny;
}
void OutputData()
{
int i, j, k, l;
fprintf(fp, "%f %f %f\n", x,y,zc);
for(i=0; i<=Nx; i++)
for(j=0; j<=Ny; j++)
{
x = xmin + i*hx; y = ymin + j*hy;
fprintf(fp, "%d %f %f %f\n", j*(Nx+1)+i+1, x, y, f(x,y));
}
k = (Nx+1)*(Ny+1);
fprintf(fp,"%d %f %f %f\n", ++k, 0.0, 0.0, 0.0);
fprintf(fp,"%d %f %f %f\n", ++k, xaxis, 0.0, 0.0);
fprintf(fp,"%d %f %f %f\n", ++k, 0.0, yaxis, 0.0);
fprintf(fp,"%d %f %f %f\n", ++k, 0.0, 0.0, zaxis);
fprintf(fp,"Faces:\n");
for(i = 0; i < Nx; i++)
for(j = 0; j < Ny; j++)
{
46
k=j*(Nx+1)+i+1; l = k+Nx+1;
fprintf(fp,"%d %d %d#\n", k, -(l+1), k+1);
fprintf(fp,"%d %d %d#\n", k+1, l+1, -k);
fprintf(fp,"%d %d %d#\n", k, -(l+1), l);
fprintf(fp,"%d %d %d#\n", l, l+1, -k);
}
k = (Nx+1)*(Ny+1);
fprintf(fp,"%d %d#\n", k+1, k+2); // x-axis
fprintf(fp,"%d %d#\n", k+1, k+3); // y-axis
fprintf(fp,"%d %d#\n", k+1, k+4); // z-axis
}

 

F(x, y) = 70  cos sqrt ( x 2  y 2 ) 
180 

-500 ≦ x ≦ 500,
-500 ≦ y ≦ 500 Nx = 20, Ny=20, zc = 0, (x,y,z): (600, 600, 100)
rho = 1000, theta = 20, phi = 60
13. Cube
// cube.dat
000
1000
47
2100
3110
4010
5001
6101
7111
8011
Faces:
2 3 7 6#
4 1 5 8#
3 4 8 7#
1 2 6 5#
6 7 8 5#
3 2 1 4#
14. Cylinder
// Cylinder.cpp
Program to generate a cylinder
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <process.h>
void main()
{
FILE *fp;
char ch, str[50];
48
float diam, r, h, delta, alpha, pi, rcos, rsin, half;
int i, i1, n;
pi = 4*atan(1.0);
fp = fopen("cylin.dat", "w");
do
{
printf("Direction of axis? (X/Y/Z) ");
ch = getchar();
ch = toupper(ch);
} while (ch != 'X' && ch != 'Y' && ch != 'Z');
printf("Diameter? ");
/*
scanf("%f", &diam); r = diam/2;
printf("Altitude? ");
scanf("%f",&h); half = h/2;
printf("Number of polygon edges? ");
scanf("%d", &n);
printf("Name of output file?");
scanf("%s", str);
fp = fopen(str, "w"); */
if (fp == NULL) { printf("File problem"); exit(1); }
delta = 2*pi/n;
fprintf(fp, "%f %f %f\n", 0, 0, -half);
for (i=1; i <= n; i++)
{
alpha = i*delta;
rcos = r*cos(alpha);
rsin = r*sin(alpha);
if (ch == 'Z')
{
fprintf(fp, "%d %f %f %f\n", i, rcos, rsin, half);
fprintf(fp, "%d %f %f %f\n", i+n, rcos, rsin, -half);
}
else
{
if (ch == 'X')
{
fprintf(fp, "%d %f %f %f\n", i, half, rcos, rsin);
fprintf(fp, "%d %f %f %f\n", i+n, -half, rcos, rsin);
}
else // ch == 'Y'
49
{
fprintf(fp, "%d %f %f %f\n", i, rsin, half, rcos);
fprintf(fp, "%d %f %f %f\n", i+n, rsin, -half, rcos);
}
}
}
fprintf(fp, "Faces:\n");
for (i=1; i<=n; i++)
fprintf(fp, "%d%s", i, (i==n? "#\n" : i%10? " ": "\n"));
for (i=1; i<=n; i++)
fprintf(fp, "%d%s", 2*n+1-i, (i==n? "#\n" : i%10? " ": "\n"));
for (i=1; i<=n; i++)
{
i1 = (i==n ? 1: i+1);
fprintf(fp, "%d %d %d %d#\n", i, i+n, i1+n, i1);
}
fclose(fp);
}
Z, 10, 15, 4
Z, 10, 15, 10
50
Z, 10, 15, 50
15. Cones and pyramids
// Cone.cpp
Program to generate a cone
#include <stdio.h>
#include <math.h>
#include <process.h>
void main()
{
FILE *fp;
51
char ch, str[50];
float diam, r, h, delta, alpha, x, y, pi;
int i, n;
pi = 4*atan(1.0);
fp = fopen("Cone.dat", "w");
printf("Diameter of the base circle? ");
scanf("%f", &diam); r = diam/2;
printf("Altitude? ");
scanf("%f",&h);
printf("Number of polygon edges? ");
scanf("%d", &n);
/*
printf("Name of output file?");
scanf("%s", str);
fp = fopen(str, "w"); */
if (fp == NULL) { printf("File problem"); exit(1); }
delta = 2*pi/n;
fprintf(fp, "%f %f %f\n", 0., 0., 0.);
for (i=1; i <= n; i++)
{
alpha = i*delta;
x = r*cos(alpha);
y = r*sin(alpha);
fprintf(fp, "%2d %f %f %f\n", i, x, y, 0.);
}
fprintf(fp, "%2d %f %f %f\n", n+1, 0., 0., h);
fprintf(fp, "Faces:\n");
for (i=n; i>=1; i--)
fprintf(fp,"%3d%s", i, (i==1? "#\n" : (i%10 == 1 ? "\n" : "")));
for (i=1; i<=n; i++)
fprintf(fp, "%2d %2d %2d#\n", i, (i==n? 1 : i+1), n+1);
fclose(fp);
}
52
16. Traditional approximation of a sphere
// Sphere.cpp
Sphere approximation with m slices, n points
#include <stdio.h>
#include <math.h>
#include <process.h>
void main()
{
FILE *fp;
char ch, str[50];
double r, theta, delphi, deltheta, rsinphi, rcosphi, x, y, z, pi, phi;
int i, j, m, n, nr, next, southpole;
/*
pi = 4*atan(1.0);
fp = fopen("Sphere.dat", "w");
printf("Enter m, the number of horizontal slices: ");
scanf("%d", &m);
printf("\nThere will be n points on each horizontal circle.\n");
printf("It is recommended to choose n about twice as large as m.\n");
printf("Enter n: "); scanf("%d", &n);
delphi = pi/m; deltheta = 2*pi/n;
printf("Radius of the sphere: "); scanf("%lf", &r);
printf("Name of output file?");
scanf("%s", str);
fp = fopen(str, "w"); */
if (fp == NULL) { printf("File problem"); exit(1); }
fprintf(fp, "%f %f %f\n", 0., 0., 0.);
// Vertex numbering:
// i = 0: 1
// i = 1: 2, 3, ..., n+1
// i = 2: n+2, n+3, ..., 2n+1
// ...
53
//
//
i = m-1: (m-2)n+2, (m-2)n+3, ..., (m-1)n+1
i = m: (m-1)n+2
fprintf(fp, "%d %f %f %f\n", 1, 0., 0., r); // i=0
for (i=1; i<m; i++)
{
phi = i*delphi;
rcosphi = r*cos(phi); rsinphi = r*sin(phi);
for (j=0; j<n; j++)
{
nr = (i-1)*n+j+2;
theta = j*deltheta;
x = rsinphi * cos(theta);
y = rsinphi * sin(theta);
z = rcosphi;
fprintf(fp,"%d %f %f %f\n", nr, x, y, z);
}
}
fprintf(fp, "%d %f %f %f\n", (m-1)*n+2, 0., 0., -r); // i=m
fprintf(fp, "Faces:\n");
for (j=2; j<=n+1; j++)
fprintf(fp, "%d %d %d#\n", 1, j, (j<n+1? j+1 : 2));
for (i=1; i<m-1; i++)
{
nr = (i-1)*n;
for (j=2; j<=n+1; j++)
{
next = (j<n+1? j+1: 2);
fprintf(fp, "%d %d %d %d#\n", nr+j, nr+n+j, nr+n+next, nr+next);
}
}
southpole = (m-1)*n+2;
nr = (m-2)*n;
for (j=2; j<=n+1; j++)
fprintf(fp, "%d %d %d#\n",nr+j, southpole, (j<n+1? nr+j+1: nr+2));
fclose(fp);
}
m = 4, n= 8
54
m=10, n=20
17. Octahedron
//Octah.dat
0 0 -1
1 0.5 0.5 0.
2 -0.5 0.5 0.
3 -0.5 -0.5 0.
4 0.5 -0.5 0.
5 0. 0. 0.707107
6 0. 0. -0.707107
Faces:
1 2 5#
2 3 5#
3 4 5#
4 1 5#
55
1 6 2#
2 6 3#
3 6 4#
4 6 1#
18. Dodecahedron
// Dodeca.cpp
This program constructs a dodecahedron and a cube in which it fits.
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <process.h>
void main()
{
FILE *fp;
char ch, str[50];
float s, a, h, v, d, tau, pi;
int i;
static float x[21], y[21], z[21]; // initially 0
pi = 4*atan(1.0);
fp = fopen("Dodeca.dat", "w");
tau = (sqrt(5.0)+1)/2;
// tau = 2*cos(pi/5)
// sometimes the letter phi is used instead of tau
s = sqrt(3-tau)/2;
// s = sin(pi/5)
a = tau * s;
h = (2*s + (tau+1)*sqrt(tau+2))/4;
// Half edge of cube
v = (tau-1) * h;
d = (tau-1) *(h-s);
printf("The twelve faces of the dodecahedron are pentagons,\n");
printf("each fitting in a circle with radius 1.\n");
printf("The sides of these pentagons have length %f.\n", 2*s);
printf("The dodecahedron fits in a cube with edges of length");
printf(" %f.\n", 2*h);
x[5] = x[7] = s;
x[6] = x[8] = -s;
x[9] = x[10] = h; x[11] = x[12] = -h;
x[13] = x[15] = x[17] = x[19] = a;
x[14] = x[16] = x[18] = x[20] = -a;
y[1] = y[3] = -s; y[2] = y[4] = s;
y[5] = y[6] = h;
y[7] = y[8] = -h;
y[13] = y[14] = y[17] = y[18] = h-d;
56
y[15] = y[16] = y[19] = y[20] = -(h-d);
z[1] = z[2] = h; z[3] = z[4] = -h;
z[9] = z[11] = s; z[10] = z[12] = -s;
z[13] = z[14] = z[15] = z[16] = v;
z[17] = z[18] = z[19] = z[20] = -v;
fp = fopen("dodeca.dat", "w");
fprintf(fp, "%f %f %f\n", 0., 0., 0.);
for (i=1; i<=20; i++)
fprintf(fp, "%3d %f %f %f\n", i, x[i], y[i], z[i]);
// The cube in which the dodecahedron fits will have the vertex
// numbers 101, 102, ..., 108:
fprintf(fp, "101 %f %f %f\n", h, -h, -h);
fprintf(fp, "102 %f %f %f\n", h, h, -h);
fprintf(fp, "103 %f %f %f\n", -h, h, -h);
fprintf(fp, "104 %f %f %f\n", -h, -h, -h);
fprintf(fp, "105 %f %f %f\n", h, -h, h);
fprintf(fp, "106 %f %f %f\n", h, h, h);
fprintf(fp, "107 %f %f %f\n", -h, h, h);
fprintf(fp, "108 %f %f %f\n", -h, -h, h);
fprintf(fp, "Faces:\n");
fprintf(fp," 1 15 9 13 2#\n");
fprintf(fp," 1 2 14 11 16#\n");
fprintf(fp," 5 6 14 2 13#\n");
fprintf(fp," 7 15 1 16 8#\n");
fprintf(fp," 19 10 9 15 7#\n");
fprintf(fp," 10 17 5 13 9#\n");
fprintf(fp," 20 8 16 11 12#\n");
fprintf(fp," 18 12 11 14 6#\n");
fprintf(fp," 3 4 17 10 19#\n");
fprintf(fp," 4 18 6 5 17#\n");
fprintf(fp," 3 20 12 18 4#\n");
fprintf(fp," 3 19 7 8 20#\n");
// The cube edges are entered as loose line segments:
fprintf(fp, "101 102#\n102 103#\n103 104#\n104 101#\n");
fprintf(fp, "105 106#\n106 107#\n107 108#\n108 105#\n");
fprintf(fp, "101 105#\n102 106#\n103 107#\n104 108#\n");
fclose(fp);
}
57
19. Icosahedron
// Icosa.cpp
Icosahedron: a regular polyhedron with 20 boundary faces,
//
which are equilateral triangules.
#include <stdio.h>
#include <math.h>
#define point(i,x,y,z) fprintf(fp, "%d %f %f %f\n",i,x,y,z)
#define face3(i,j,k) fprintf(fp,"%d %d %d#\n", i,j,k)
#define pi (4*atan(1.0))
void main()
{
FILE *fp;
char ch, str[50];
float s, r, alpha, tau;
int i;
tau = (sqrt(5.0)+1)/2; // tau = 2*cos(pi/5);
s = sqrt(3-tau)/2;
// s = sin(pi/5), pi/5 = 36 degrees
r = tau - 0.5;
printf("Ten of the twelve vertices of the icosahedron\n");
printf("lie on two horizontal pentagons, either of which\n");
printf("fits in a circle with radius 1.\n");
printf("These two pentagons lie a distance 1 apart.\n");
printf("The edges have length %f.\n", 2*s);
printf("The icosahedron fits in a sphere with radius %f.\n",r);
58
fp = fopen("Icosa.dat", "w");
fprintf(fp, "%f %f %f\n", 0., 0., 0.);
point(1, 0., 0., r); // North pole
for (i=0; i<5; i++)
{
alpha = -pi/5+i*pi/2.5; // In degree: -36+i*72
point(2+i, cos(alpha), sin(alpha), 0.5);
}
for (i=0; i<5; i++)
{
alpha = i*pi/2.5;
point(7+i, cos(alpha), sin(alpha), -0.5);
}
point(12, 0., 0., -r); // South pole
fprintf(fp, "Faces:\n");
for (i=0; i<5; i++) face3(1, 2+i, (i<4 ? 3+i : 2));
for (i=0; i<5; i++) face3(2+i, 7+i, (i<4 ? 3+i : 2));
for (i=0; i<5; i++) face3(7+i, 12, (i<4 ? 8+i : 7));
fclose(fp);
}
20. Sphere approximation with 80 triangles
// Sph80.cpp
// Polyhedron with 80 triangular faces to approximate a sphere.
// It is based on an icosahedron, which is a regular polyhedron
// with 20 equilateral triangules as bounding faces. Instead of
// each of these triangles, four smaller triangles are used,
// which gives 20 x 4 = 80 0f these small triangles (no eqilateral).
59
// For each equilateral triangle of the icosahedron the midpoints
// of its three sides are projected onto we obtain the four smaller
// triangles by connecting neighboring points.
#include <stdio.h>
#include <math.h>
#include <process.h>
#define pi (4*atan(1.0))
void point(int i, float x, float y, float z);
void subdivide(int A, int B, int C);
void storeface(int i, int j, int k);
void midpnt(int B, int C, int *pP, float x, float y, float z);
int npoints;
typedef struct Point3Struct {float x, y, z; } Point3;
Point3 pnt[43];
int nface = 0;
struct {int i, j, k; } fc[80];
int nedge = 0;
struct { int i, j, P; } edges[120];
FILE *fp;
void main()
{
float r, alpha, tau; int i, l;
tau = (sqrt(5.0)+1)/2; // tau = 2*cos(pi/5);
r = tau - 0.5;
fp = fopen("Sph80.dat", "w");
fprintf(fp, "%f %f %f\n", 0., 0., 0.);
point(1, 0., 0., 1.0); // North pole
for (i=0; i<5; i++)
{
alpha = -pi/5+i*pi/2.5; // In degree: -36+i*72
point(2+i, cos(alpha)/r, sin(alpha)/r, 0.5/r);
}
for (i=0; i<5; i++)
{
alpha = i*pi/2.5;
point(7+i, cos(alpha)/r, sin(alpha)/r, -0.5/r);
60
}
point(12, 0., 0., -1.0);
// South pole
npoints = 12;
for (i=0; i<5; i++) subdivide(1, 2+i, (i<4? 3+i : 2));
for (i=0; i<5; i++) subdivide(2+i, 7+i, (i<4? 3+i : 2));
for (i=0; i<5; i++) subdivide(7+i, (i<4? 8+i : 7), (i<4 ? 3+i : 2));
for (i=0; i<5; i++) subdivide(7+i, 12, (i<4 ? 8+i : 7));
fprintf(fp, "Faces:\n");
for (l=0; l<80; l++) fprintf(fp, "%d %d %d#\n", fc[l].i, fc[l].j, fc[l].k);
fclose(fp);
}
void midpnt(int B, int C, int *pP, float x, float y, float z)
// Point (x, y, z) is midpoint of BC. If it is a new vertex, store it and
// write it to the object file, using a new vertex number. If not, find
// its vertex number. The vertex number is to be assigned to *pP anyway.
{
int tmp, e;
if (C < B) { tmp = B; B = C; C = tmp; }
// B, C in increasing order, for the sake of uniqueness
for (e=0; e<nedge; e++)
if(edges[e].i == B && edges[e].j == C) break;
if (e == nedge)
// Not found, so we have a new vertex
{
edges[e].i = B; edges[e].j = C;
edges[e].P = *pP = ++npoints;
nedge++;
point(*pP, x, y, z);
}
else *pP = edges[e].P; // Edge BC has been dealt with before, so
// the vertex is not new
}
void point(int i, float x, float y, float z)
{
fprintf(fp, "%d %f %f %f\n", i, x, y, z);
pnt[i].x = x; pnt[i].y = y; pnt[i].z = z;
}
void subdivide(int A, int B, int C)
61
// Divide triangle ABC into four smaller triangles
{
float xP, yP, zP, xQ, yQ, zQ, xR, yR, zR;
int P, Q, R;
static float d = -1;
// d is equal to -1 only before the first call of this function;
// after this, d will have its correct value (between 0 and 1),
// namely the distance between any midpoint and the center of the
// sphere. We project all midpoints onto the sphere (with radius 1)
// by dividing their coordinates by d.
xP = (pnt[B].x + pnt[C].x)/2;
yP = (pnt[B].y + pnt[C].y)/2;
zP = (pnt[B].z + pnt[C].z)/2;
xQ = (pnt[C].x + pnt[A].x)/2;
yQ = (pnt[C].y + pnt[A].y)/2;
zQ = (pnt[C].z + pnt[A].z)/2;
xR = (pnt[B].x + pnt[A].x)/2;
yR = (pnt[B].y + pnt[A].y)/2;
zR = (pnt[B].z + pnt[A].z)/2;
if (d < 0) d = sqrt(xP*xP+yP*yP+zP*zP); // 0 < d < 1
xP /= d;
yP /= d; zP /= d;
xQ /= d;
yQ /= d; zQ /= d;
xR /= d;
yR /= d; zR /= d;
midpnt(B,C,&P,xP,yP,zP);
midpnt(C,A,&Q,xQ,yQ,zQ);
midpnt(A,B,&R,xR,yR,zR);
storeface(A,R,Q);
storeface(R,B,P);
storeface(Q,P,C);
storeface(Q,R,P);
}
void storeface(int i, int j, int k)
{
fc[nface].i = i;
fc[nface].j = j;
fc[nface].k = k;
nface++;
}
62
21. Three-dimensional rotations
// Genrota.cpp
#include <stdio.h>
#include <math.h>
#include <process.h>
#define pi (4*atan(1.0))
#define point(i,P) fprintf(fp2,"%d %f %f %f\n",i,P.x,P.y,P.z)
#define face3(i,j,k) fprintf(fp2,"%d %d %d#\n", i,j,k)
typedef struct Point3Struct {double x, y, z; } Point3;
void initrotate(Point3 A, Point3 V, double alpha);
void rotate(Point3 A, Point3 *P1);
double r11, r12, r13, r21, r22, r23, r31, r32, r33, r41, r42, r43;
void main()
{
FILE *fp1, *fp2; Point3 A, P1, V;
double alphadeg, alpha;
int nr, ch, n=0;
/* char str[30];
printf("Input file: "); scanf("%s", str); fp1 = fopen(str,"r");
printf("Output file: "); scanf("%s", str); fp2 = fopen(str,"w"); */
fp1 = fopen("gen.in","r");
fp2 = fopen("gen.dat","w");
if (fp1 == NULL || fp2 == NULL)
{
printf("File program"); exit(1); }
printf("Enter xA, yA, zA: ");
scanf("%lf %lf %lf", &(A.x), &(A.y), &(A.z));
printf("ENter V.x, V.y, V.z: ");
63
scanf("%lf %lf %lf", &(V.x), &(V.y), &(V.z));
printf("Enter alpha (in degrees): ");
scanf("%lf", &alphadeg);
alpha = alphadeg * pi/180; // alpha in radians
initrotate(A, V, alpha);
fscanf(fp1, "%lf %lf %lf",&(A.x), &(A.y), &(A.z));
fprintf(fp2,"%lf %lf %lf\n", A.x, A.y, A.z);
while (fscanf(fp1, "%d %lf %lf %lf",&nr, &(A.x), &(A.y), &(A.z)) == 4)
{
rotate(A,&P1); n++;
point(nr, P1);
}
while (ch = getc(fp1), ch != EOF) putc(ch,fp2);
fclose(fp1); fclose(fp2);
printf("Ready! %d points rotated\n", n);
}
void initrotate(Point3 A, Point3 V, double alpha)
{
double rho, theta, cal, sal, cph, sph, cth, sth, cph2, sph2, cth2, sth2, call;
cal = cos(alpha); sal = sin(alpha);
call = 1.0-cal;
rho = sqrt(V.x*V.x+V.y*V.y+V.z*V.z);
if (fabs(rho) < 1e-12) {
theta = 0.0; cph = 1.0; sph = 0.0; }
else
{
if (fabs(V.x) < 1e-12) theta = (V.y >= 1e-5? 0.5*pi : 1.5*pi);
else
{
theta = atan(V.y/V.x); if (V.x < 0) theta += pi;
cph = V.z/rho; sph = sqrt(1.0-cph*cph);
// cph = cos(phi); sph = sin(phi);
}
cth = cos(theta);
cph2 = cph*cph;
cth2 = cth*cth;
sth = sin(theta);
sph2 = 1.0-cph2;
sth2 = 1.0-cth2;
r11 = (cal*cph2 + sph2)*cth2+cal*sth2;
r12 = sal*cph+call*sph2*cth*sth;
r13 = sph*(cph*cth*call-sal*sth);
r21 = sph2*cth*sth*call-sal*cph;
r22 = sth2*(cal*cph2+sph2)+cal*cth2;
r23 = sph*(cph*sth*call+sal*cth);
r31 = sph*(cph*cth*call+sal*sth);
r32 = sph*(cph*sth*call-sal*cth);
r33 = cal*sph2+cph2;
64
}
r41 = A.x-A.x*r11-A.y*r21-A.z*r31;
r42 = A.y-A.x*r12-A.y*r22-A.z*r32;
r43 = A.z-A.x*r13-A.y*r23-A.z*r33;
printf("%f %f %f\n",r11, r12, r13);
printf("%f %f %f\n",r21, r22, r23);
printf("%f %f %f\n",r31, r32, r33);
printf("%f %f %f\n",r41, r42, r43);
}
void rotate(Point3 A, Point3 *P1)
{
P1->x = A.x*r11+A.y*r21+A.z*r31+r41;
P1->y = A.x*r12+A.y*r22+A.z*r32+r42;
P1->z = A.x*r13+A.y*r23+A.z*r33+r43;
}
//
gen.in
// gen.dat
0.0 0.0 0.0
0.000000 0.000000 0.000000
1 1.0 0.0 0.0
1 1.780631 0.982662 0.000000
2 1.0 2.0 0.0
2 -0.151221 1.500301 0.000000
3 0.0 2.0 0.0
3 -0.410040 0.534375 0.000000
4 0.0 0.0 0.0
4 1.521812 0.016737 0.000000
5 1.0 0.0 3.0
5 1.780631 0.982662 3.000000
6 1.0 2.0 3.0
6 -0.151221 1.500301 3.000000
7 0.0 2.0 3.0
7 -0.410040 0.534375 3.000000
8 0.0 0.0 3.0
8 1.521812 0.016737 3.000000
9 0.0 0.0 0.0
9 1.521812 0.016737 0.000000
10 4.0 0.0 0.0
10 2.557088 3.880440 0.000000
11 0.0 4.0 0.0
11 -2.341892 1.052013 0.000000
12 0.0 0.0 4.0
12 1.521812 0.016737 4.000000
Faces:
Faces:
1 2 6 5#
1 2 6 5#
2 3 7 6#
2 3 7 6#
3 4 8 7#
3 4 8 7#
4 1 5 8#
4 1 5 8#
5 6 7 8#
5 6 7 8#
1 4 3 2#
1 4 3 2#
9 10#
9 10#
9 11#
9 11#
9 12#
9 12#
65
22. B-spline space curves
// Curve3.cpp
// B-spline curve fitting in 3D. The program reads an input file
// and writes an output file.
#include <stdio.h>
#include <math.h>
#include <process.h>
#define Horner(t, a3, a2, a1, a0) ((((a3)*(t)+(a2))*(t)+(a1))*(t)+(a0))
typedef struct Point3Struct {float x, y, z; } Point3;
typedef float Coef;
typedef int Index;
void main()
{
char infil[30], outfil[30];
Index i, j; int m=0, N, k, first = 0;
float t; Coef a[4], b[4], c[4];
Point3 A, B, C, D, dum, *P, Q;
FILE *fpin, *fpout;
// printf("Input file: "); scanf("%s", infil);
//
printf("Output file: "); scanf("%s", outfil);
printf("Enter N, the number of intervals between two successive given points: ");
scanf("%d", &N);
fpin = fopen("cable.dat","r");
if (fpin == NULL) {
printf("File not available"); exit(1);
}
while (fscanf(fpin,"%*d %f %f %f", &(dum.x), &(dum.y), &(dum.z)) >0) m++;
fclose(fpin);
fpin = fopen("cable.dat", "r");
P = new Point3[m+1];
66
for (i = 1; i <= m; i++)
fscanf(fpin, "%*d %f %f %f", &((P+i)->x), &((P+i)->y), &((P+i)->z));
fclose(fpin);
fpout = fopen("cable.out", "w");
for (i = 2; i < m-1; i++)
{
A = P[i-1]; B = P[i]; C = P[i+1];
a[3] = (-A.x+3*(B.x-C.x)+D.x)/6.0;
a[2] = (A.x-2*B.x+C.x)/2.0;
a[1] = (C.x-A.x)/2.0;
a[0] = (A.x+4*B.x+C.x)/6.0;
D = P[i+2];
b[3] = (-A.y+3*(B.y-C.y)+D.y)/6.0;
b[2] = (A.y-2*B.y+C.y)/2.0;
b[1] = (C.y-A.y)/2.0;
b[0] = (A.y+4*B.y+C.y)/6.0;
c[3] = (-A.z+3*(B.z-C.z)+D.z)/6.0;
c[2] = (A.z-2*B.z+C.z)/2.0;
c[1] = (C.z-A.z)/2.0;
c[0] = (A.z+4*B.z+C.z)/6.0;
for(j = first; j <= N; j++)
{
t = float(j)/float(N);
Q.x = Horner(t, a[3], a[2], a[1], a[0]);
Q.y = Horner(t, b[3], b[2], b[1], b[0]);
Q.z = Horner(t, c[3], c[2], c[1], c[0]);
fprintf(fpout, "%d %f %f %f\n", (i-2)*N+j+1, Q.x, Q.y, Q.z);
}
first = 1;
}
fprintf(fpout,"Faces:\n");
k = (m-3)*N+1;
for (j = 1; j < k; j++) fprintf(fpout, "%d %d#\n", j, j+1);
fclose(fpout);
}
// cable.dat
1 0 -100 12
2 0 -70 10
3 -15 -30 8
4 15 0 15
5 0 20 22
Faces:
1 2#
2 3#
3 4#
4 5#
5 6#
67
6 -15 30 0
7 0 20 -22
6 7#
7 8#
8 15 0 -15
9 -15 -30 -8
10 0 -70 -50
11 0 0 -100
12 0 70 -50
13 15 30 -8
14 -15 0 -15
15 0 -20 -22
16 15 -30 0
8 9#
9 10#
10 11#
11 12#
12 13#
13 14#
14 15#
15 16#
16 17#
17 0 -20 22
18 -15 0 15
19 15 30 8
20 0 70 10
21 0 100 12
17 18#
18 19#
19 20#
20 21#
23. Cables
/* CABLE: This program reads a file that represents a space curve, and it writes a file that
represents a cable. The circular cable section will be a regular polygon with n vertices; it
approximates a circle with radius R. Both n and R are read from the keyboard.
The program is to be linked together with the module TRAFO, in which the functions
‘initrotate' and 'rotate' are defined.
*/
#include <stdio.h>
#include <math.h>
68
#include <process.h>
#include <stdlib.h>
void initrotate (double al, double a2, double a3,
double vl, double v2, double v3, double alpha);
void rotate (double x, double y, double z,
double *pxl, double *pyl, double *pzl);
int zero (double x) ;
double *getdouble(int n);
double *enlarge (double *px, int N) ;
void ermes (char *s);
void main()
{
char infil[30], outfil[30];
int i, n, j, m, jn, jn0, k, tablesize;
double R, *x, *y, *z, xC0, yC0, zC0, xC1, yC1, zC1,
xC2, yC2, zC2, *xC, *yC, *zC,
a, b, c, d, rx, ry, rz, pi, theta, Len,
xA, yA, zA, xB, yB, zB, dx, dy, dz, d0, c1, c2, c0,
xM, yM, zM, e1, e2, e0, denom, lambda, mu, xP, yP, zP,
xAP, yAP, zAP, xBP, yBP, zBP, v1, v2, v3,
cosphi, phi;
FILE *fpin, *fpout;
printf ("Input file: "); scanf("%s", infil);
fpin = fopen (infil, "r");
if (fpin == NULL)
ermes ("File not available");
if (fscanf(fpin, "%*d %lf %lf %lf", &xC0, &yC0, &zC0) != 3 ||
fscanf(fpin, "%*d %lf %lf %lf", &xC1, &yC1, &zC1) != 3 ||
fscanf(fpin, "%*d %lf %lf %lf", &xC2, &yC2, &zC2) != 3)
ermes ("Input file incorrect") ;
printf ("Output file: "); scanf("%s", outfil);
fpout = fopen(outfil, "w") ;
printf ("How many points on each circle? ");
scanf("%d", &n);
printf ("Radius: "); scanf("%lf", &R);
a=xC2-xC0; b=yC2-yC0; c=zC2-zC0; d=a*xC1+b*yC1+c*zC1;
/* First circle has center (xCI, yCl, zCI), radius R, and
it lies in plane ax+by+cz = d*/
x = getdouble(n); y = getdouble(n); z = getdouble(n);
if (zero(a) && zero(b)) { rx=0; ry=c; rz=-b;}
69
else {rx=b; ry=-a; rz=0;}
Len=sqrt(rx*rx+ry*ry+rz*rz);
rx/=Len; ry/=Len; rz/=Len;
/* (rx, ry, rz) is a unit vector perpendicular to (a, b, c) */
x[0]=xC1+rx*R; y[0]=yC1+ry*R; z[0]=zC1+rz*R;
pi=4.0*atan(1.0);
theta=2*pi/n;
/* Computation of n points on the first circle: */
initrotate(xC1, yC1, zC1, a, b, c, theta);
for (i=1; i<n; i++) rotate(x[i-1], y[i-1], z[i-1], x+i, y+i, z+i);
/* Count number of circles (number of points minus I read from input file): */
m = 2;
while (fscanf(fpin, "%*d %lf %lf %lf", &xC0, &yC0, &zC0) == 3)
tablesize = m*n;
x = enlarge(x, tablesize);
y = enlarge(y, tablesize);
z = enlarge(z, tablesize);
fclose(fpin); fpin = fopen(infil, "r") ;
/* Rewind */
fscanf(fpin, "%*d %lf %lf %lf", &xC0, &yC0, &zC0);
/* Skip */
xC = getdouble(m);
m++;
yC = getdouble(m);
zC = getdouble(m);
for (j=0; j<m; j++) fscanf(fpin, "%*d %lf %lf %lf", xC+j, yC+j, zC+j);
/* (xC [0], yC[0], zC[0]) is now the center of the given circle, lying in plane
ax+by+cz =d, and with radius R. The n relevant points on this circle have already
been computed; their coordinates are
x[0], y[0], z[0], ..., x[n-l], y[n-l], z[n-l].
The other m-l circles will be derived from this first one by means of rotations.
fclose(fpin);
for (j=1; j<m; j++)
{
jn=j*n; jn0=jn-n;
xA=xC[j-1] ; yA=yC[j-1] ; zA=zC[j-1] ;
xB=xC[j]; yB=yC[j]; zB=zC[j];
dx=xB-xA; dy=yB-yA; dz=zB-zA;
c1=a*a+b*b+c*c;
c2=a*dx+b*dy+c*dz;
c0=d-a*xA-b*yA-c*zA;
xM=0.5*(xA+xB); yM=0.5*(yA+yB); zM=0.5*(zA+zB);
70
*/
d0=dx*xM+dy*yM+dz*zM;
e1=dx*a+dy*b+dz*c;
e2=dx*dx+dy*dy+dz*dz;
e0=d0-dx*xA-dy*yA-dz*zA;
denom=c1*e2-c2*e1;
if (fabs(denom) < 1e-12)
{ /* Direction does not change.
Instead of using a point P infinitely far
away, we perform a simple translation:
for (i=0; i<n; i++)
{
*/
x[jn+i] = x[jn0+i] + dx;
y[jn+i] = y[jn0+i] + dy;
z[jn+i] = z[jn0+i] + dz;
}
}
else
/* Direction changes.
The polygon will be rotated through the angle phi
about vector v passing through point P:
*/
{
lambda=(c0*e2-c2*e0)/denom;
mu= (c1*e0-c0*e1)/denom;
xP=xA+lambda *a+mu*dx;
yP=yA+lambda *b+mu*dy;
zP=zA+lambda*c+mu*dz ;
/* Point P (of intersection of three planes) is
center of rotation
*/
xAP=xA-xP; yAP=yA-yP; zAP=zA-zP;
xBP=xB-xP; yBP=yB-yP; zBP=zB-zP;
v1=yAP*zBP-yBP*zAP;
v2=xBP*zAP-xAP*zBP;
v3=xAP*yBP-xBP*yAP;
/* (vl, v2, v3) is direction of axis of rotation */
cosphi=(xAP*xBP+yAP*yBP+zAP*zBP)/
sqrt ( (xAP*xAP+yAP*yAP+zAP*zAP) *
(xBP*xBP+yBP*yBP+zBP*zBP) );
phi = (cosphi == 0 ? 0.5*pi :
71
atan(sqrt(1.0-cosphi*cosphi)/cosphi) ) ;
/* phi is the angle of rotation */
initrotate(xP, yP, zP, v1, v2, v3, phi);
for (i=0; i<n; i++)
rotate(x[jn0+i], y[jn0+i], z[jn0+i], x+jn+i, y+jn+i, z+jn+i);
initrotate(0.0, 0.0, 0.0, v1, v2, v3, phi);
rotate(a, b, c, &a, &b, &c) ;
}
d=a*xC[j]+b*yC[j]+c*zC[j] ;
}
if (fpout == NULL) ermes ("Problem with output file");
for (k=0; k<m*n; k++)
fprintf (fpout, "%d %f %f %f\n", k+1, x[k], y[k], z[k]);
fprintf (fpout, "Faces:\n");
for (k=n-1; k>=0; k--) fprintf(fpout, " %d", k+1);
fprintf ( fpout, "#\n" ) ;
for (k=(m-1)*n; k<m*n; k++) fprintf(fpout, " %d", k+1);
fprintf( fpout, "#\n\n" ) ;
for (j=1; j<m; j++)
{
jn=j*n+1; jn0=jn-n;
for (i=0; i<n-1; i++)
{
fprintf(fpout, " %d %d %d#\n", jn+i+1, -(jn0+i), jn0+i+1) ;
fprintf(fpout, " %d %d %d#\n", jn0+i, -(jn+i+1), jn+i);
}
fprintf(fpout, " %d %d %d#\n\n", jn, -(jn0+n-1), jn0);
fprintf(fpout, " %d %d %d#\n\n", jn0+n-1, -jn, jn+n-1);
}
fclose (fpout);
}
int zero (double x)
{ return fabs(x) < 1e-5;}
double *getdouble(int n)
{
double *p;
p = new double[n];
if (p == NULL) ermes ("Not enough memory");
72
return p;
}
double *enlarge (double *px, int N)
{
px = (double *)realloc(px, N*sizeof(double));
if (px == NULL) ermes("Not enough memory") ;
return px;
}
void ermes (char *s)
{ printf(s); exit (1); }
/* CABLE: This program reads a file that represents a space curve, and it writes a file that
represents a cable. The circular cable section will be a regular polygon with n vertices; it
approximates a circle with radius R. Both n and R are read from the keyboard.
The program is to be linked together with the module TRAFO, in which the functions
‘initrotate' and 'rotate' are defined.
*/
#include <stdio.h>
#include <math.h>
#include <process.h>
#include <stdlib.h>
typedef struct Point3Struct {float x, y, z; } Point3;
typedef Point3 Vector3;
typedef int Index;
#define Length2(P) ((P.x*P.x)+(P.y*P.y)+(P.z*P.z))
#define Length(P)
(sqrt(Length2(P)))
#define pi (4.0*atan(1.0))
Point3 V3Sub(Vector3 p, Vector3 q);
Point3 V3Add(Vector3 p, Vector3 q);
float V3Dot(Vector3 p, Vector3 q);
Vector3 V3Cross(Vector3 a, Vector3 b);
Vector3 V3Normalize(Vector3 v);
int zero(float x) ;
Point3 *enlarge(Point3 *px, int N) ;
void ermes(char *s);
void initrotate(Point3 A, Point3 V, float alpha);
73
void rotate(Point3 A, Point3 *P1);
float r11, r12, r13, r21, r22, r23, r31, r32, r33, r41, r42, r43;
void main()
{
char infil[30], outfil[30];
Index i, j, k;
int n, m, mn, jn, jn0, tablesize;
Point3 C0, C1, C2, *C, A, B, M, P, AP, BP, r, *T, d;
Vector3 Ce, V;
float radius, d1,theta, d0, c1, c2, c0, e1, e2, e0, denom, lambda, mu, cosphi, phi;
FILE *fpin, *fpout;
// printf ("Input file: "); scanf("%s", infil);
fpin = fopen("cable.in", "r");
if (fpin == NULL)
ermes ("File not available");
if (fscanf(fpin, "%*d %f %f %f", &(C0.x), &(C0.y), &(C0.z)) != 3 ||
fscanf(fpin, "%*d %f %f %f", &(C1.x), &(C1.y), &(C1.z)) != 3 ||
fscanf(fpin, "%*d %f %f %f", &(C2.x), &(C2.y), &(C2.z)) != 3)
ermes ("Input file incorrect") ;
// printf ("Output file: "); scanf("%s", outfil);
fpout = fopen("cable.out", "w") ;
printf ("How many points on each circle? ");
scanf("%d", &n);
printf ("Radius: "); scanf("%f", &radius);
Ce = V3Sub(C2, C0);
d1 = V3Dot(Ce, C1);
/* First circle has center (C1.x, C1.y, C1.z), radius radius, and
it lies in plane ax+by+cz = d*/
T = new Point3[n];
// Point3 T[n]
if (zero(Ce.x) && zero(Ce.y)) { r.x = 0; r.y = Ce.z; r.z = -Ce.y;}
else { r.x = Ce.y; r.y = -Ce.x; r.z = 0;}
r = V3Normalize(r);
/* (rx, ry, rz) is a unit vector perpendicular to (a, b, c)
T[0].x = C1.x+r.x*radius; T[0].y = C1.y+r.y*radius;
T[0].z = C1.z+r.z*radius;
theta = 2*pi/n;
/* Computation of n points on the first circle: */
initrotate(C1, Ce, theta);
for (i = 1; i < n; i++) rotate(T[i-1],&(T[i]));
/* Count number of circles
74
*/
(number of points minus I read from input file): */
m = 2;
while (fscanf(fpin, "%*d %f %f %f", &(C0.x), &(C0.y), &(C0.z)) == 3) m++;
tablesize = m*n;
T = enlarge(T, tablesize);
fclose(fpin); fpin = fopen("cable.in", "r") ;
/* Rewind */
fscanf(fpin, "%*d %f %f %f", &(C0.x), &(C0.y), &(C0.z));
/* Skip */
C = new Point3[m]; // Point3 C[m]
for (j = 0; j < m; j++) fscanf(fpin, "%*d %f %f %f", &(C[j].x), &(C[j].y), &(C[j].z));
/* (xC [0], yC[0], zC[0]) is now the center of the given circle, lying in plane
ax+by+cz =d, and with radius R. The n relevant points on this circle have already
been computed; their coordinates are
x[0], y[0], z[0], ..., x[n-l], y[n-l], z[n-l].
The other m-l circles will be derived from this first one by means of rotations. */
fclose(fpin);
for (j = 1; j < m; j++)
{
jn=j*n; jn0=jn-n;
A = C[j-1];
B = C[j];
d = V3Sub(B, A);
c1 = Length2(Ce);
c2 = V3Dot(Ce, d);
c0 = d1-V3Dot(Ce, A);
M.x=0.5*(A.x+B.x); M.y=0.5*(A.y+B.y); M.z=0.5*(A.z+B.z);
d0= V3Dot(d, M);
e1 = V3Dot(d, Ce);
e2 = Length2(d);
e0 = d0-V3Dot(d, A);
denom = c1*e2-c2*e1;
if (fabs(denom) < 1e-12)
{ /* Direction does not change.
Instead of using a point P infinitely far
away, we perform a simple translation:
*/
for (i=0; i<n; i++)
T[jn+i] = V3Add(T[jn0+i], d);
}
else
/* Direction changes.
The polygon will be rotated through the angle phi
about vector v passing through point P:
*/
{
lambda = (c0*e2-c2*e0)/denom;
75
mu = (c1*e0-c0*e1)/denom;
P.x = A.x + lambda*Ce.x + mu*d.x;
P.y = A.y + lambda*Ce.y + mu*d.y;
P.z = A.z + lambda*Ce.z + mu*d.z ;
/* Point P (of intersection of three planes) is center of rotation */
AP = V3Sub(A, P);
BP = V3Sub(B, P);
V = V3Cross(AP, BP);
/* (V.x, V.y, V.z) is direction of axis of rotation */
cosphi = V3Dot(AP,BP)/(Length(AP) * Length(BP));
phi = (cosphi == 0 ? 0.5*pi : atan(sqrt(1.0-cosphi*cosphi)/cosphi) ) ;
/* phi is the angle of rotation */
initrotate(P, V, phi);
for (i = 0; i < n; i++)
P.x = P.y = P.z = 0.0;
initrotate(P, V, phi);
rotate(Ce, &(Ce)) ;
rotate(T[jn0+i], &(T[jn+i]));
}
d1 = V3Dot(Ce, C[j]);
}
if (fpout == NULL) ermes ("Problem with output file");
mn = m*n;
for (k = 0; k < mn; k++)
fprintf (fpout, "%d %f %f %f\n", k+1, T[k].x, T[k].y, T[k].z);
fprintf (fpout, "Faces:\n");
for (k = n-1; k >= 0; k--) fprintf(fpout, " %d", k+1);
fprintf ( fpout, "#\n" ) ;
for (k = (m-1)*n; k < mn; k++) fprintf(fpout, " %d", k+1);
fprintf( fpout, "#\n\n" ) ;
for (j = 1; j < m; j++)
{
jn = j*n+1; jn0 = jn-n;
for (i = 0; i < n-1; i++)
{
fprintf(fpout, " %d %d %d#\n", jn+i+1, -(jn0+i), jn0+i+1) ;
fprintf(fpout, " %d %d %d#\n", jn0+i, -(jn+i+1), jn+i);
}
fprintf(fpout, " %d %d %d#\n\n", jn, -(jn0+n-1), jn0);
fprintf(fpout, " %d %d %d#\n\n", jn0+n-1, -jn, jn+n-1);
}
fclose (fpout);
76
}
int zero (float x)
{ return fabs(x) < 1e-5;}
Point3 *enlarge (Point3 *px, int N)
{
px = (Point3 *)realloc(px, N*sizeof(Point3));
if (px == NULL) ermes("Not enough memory") ;
return px;
}
void ermes (char *s)
{ printf(s); exit (1); }
Vector3 V3Sub(Vector3 p, Vector3 q)
{
Vector3 r;
r.x = p.x - q.x; r.y = p.y - q.y; r.z = p.z - q.z;
}
Vector3 V3Add(Vector3 p, Vector3 q)
{
Vector3 r;
r.x = p.x + q.x; r.y = p.y + q.y; r.z = p.z + q.z;
}
return(r);
return(r);
float V3Dot(Vector3 p, Vector3 q)
{ return((p.x*q.x)+(p.y*q.y)+(p.z*q.z)); }
Vector3 V3Normalize(Vector3 v)
{
float len = Length(v);
if (len != 0.0) {v.x /= len;
return(v);
v.y /= len; v.z /= len;};
}
/*回返 c = a × b*/
Vector3 V3Cross(Vector3 a, Vector3 b)
{
77
Vector3 c;
c.x = (a.y * b.z) - (a.z * b.y);
c.y = (a.z * b.x) - (a.x * b.z);
c.z = (a.x * b.y) - (a.y * b.x);
return (c);
}
void initrotate(Point3 A, Point3 V, float alpha)
{
float rho, theta, cal, sal, cph, sph, cth, sth, cph2, sph2, cth2,
sth2, call;
cal = cos(alpha); sal = sin(alpha);
call = 1.0-cal;
rho = Length(V);
if (rho == 0.0)
{ theta = 0.0; cph = 1.0; sph = 0.0; }
else
{
if (V.x == 0.0)
theta = (V.y >= 0.0? 0.5*pi : 1.5*pi);
else
{
theta = atan(V.y/V.x);
if (V.x<0) theta += pi;
}
cph = V.z/rho; sph = sqrt(1.0-cph*cph);
}
cth = cos(theta); sth = sin(theta);
cph2 = cph*cph;
sph2 = 1.0-cph2;
cth2 = cth*cth;
sth2 = 1.0-cth2;
r11 = (cal*cph2 + sph2)*cth2+cal*sth2;
r12 = sal*cph+call*sph2*cth*sth;
r13 = sph*(cph*cth*call-sal*sth);
r21 = sph2*cth*sth*call-sal*cph;
r22 = sth2*(cal*cph2+sph2)+cal*cth2;
r23 = sph*(cph*sth*call+sal*cth);
r31 = sph*(cph*cth*call+sal*sth);
r32 = sph*(cph*sth*call-sal*cth);
r33 = cal*sph2+cph2;
r41 = A.x-A.x*r11-A.y*r21-A.z*r31;
r42 = A.y-A.x*r12-A.y*r22-A.z*r32;
r43 = A.z-A.x*r13-A.y*r23-A.z*r33;
78
// cph = cos(phi);
sph = sin(phi);
}
void rotate(Point3 A, Point3 *P1)
{
P1->x = A.x*r11+A.y*r21+A.z*r31+r41;
P1->y = A.x*r12+A.y*r22+A.z*r32+r42;
P1->z = A.x*r13+A.y*r23+A.z*r33+r43;
}
24. B-spline surfaces
/* BSPLSURF: B-spline surface.
This program expects a D3D object, file in which a grid of points is
defined. The program asks the user to enter m and n: there must be
exactly mn points in the file, numbered 1, 2, ..., mn. It is assumed
that these points are arranged in a grid as follows:
1
2
...
m
m+1
m+2
...
2m
2m+1
2m+2
...
3m
.
.
.
(n-l)m+1
.
(n-1)+2
...
mn
Neither m nor n must be less than 4. The position of the points in 3D
space is free: no two points need have the same x-, y-, or z-coordinates.
If the object file contains a section beginning with "Faces:", then this
section is ignored. Two integers M and N are to be entered; they denote
79
numbers of intervals used in the surface-fitting process. There will be
M intervals between the points 1 and 2, and N intervals between the points
1 and m+1, and so on. The B-spline curved surface that approximates the
given points is written to an output file in D3D format.
*/
#include <stdio.h>
#include <process.h>
void main()
{
FILE *fp1, *fp2;
char str[30] ;
float *xx, *yy, *zz, x, y, z, v, u, u2, u3,
a00, a01, a02, a03,
a10, a11, a12, a13,
a20, a21, a22, a23,
a30, a31, a32, a33,
b00, b01, b02, b03,
b10, b11, b12, b13,
b20, b21, b22, b23,
b30, b31, b32, b33,
c00, c01, c02, c03,
c10, c11, c12, c13,
c20, c21, c22, c23,
c30, c31, c32, c33,
x00, x01, x02, x03,
x10, x11, x12, x13,
x20, x21, x22, x23,
x30, x31, x32, x33,
y00, y01, y02, y03,
y10, y11, y12, y13,
y20, y21, y22, y23,
y30, y31, y32, y33,
z00, z01, z02, z03,
z10, z11, z12, z13,
z20, z21, z22, z23,
z30, z31, z32, z33;
int size, i,j,k, l, m, n, M, N, mn, I, J, A, B, C, ii, jj, nn, mm, P,
h00, h01, h02, h03,
h10, h11, h12, h13,
h20, h21, h22, h23,
h30, h31, h32, h33;
do
{
printf ("Enter m and n (both at least 4): ");
scanf ("%d %d", &m, &n);
} while (m < 4 || n < 4);
printf ("Input file:
"); scanf("%s", str);
fp1 = fopen (str, "r");
printf ("Output file:
"); scanf("%s", str);
fp2 = fopen (str, "w");
if (fp1 == NULL || fp2 == NULL)
{
printf ("File problem"); exit(1);
}
mn = m * n;
xx = new float[mn+1]; yy = new float[mn+1]; zz =new float[mn+1];
for (l = 0; l < mn; l++)
{
if (fscanf(fp1, "%d %f %f %f", &k, &x, &y, &z) != 4)
{
printf ("Too few points in file"); exit (1); }
80
if (k < 1 || k > mn)
{
printf ("Point number %d incorrect", k); exit(1);
}
xx[k] = x; yy[k] = y; zz[k] = z;
}
fclose(fp1);
printf ("Enter M and N: "); scanf("%d %d", &M, &N);
/* Let us imagine that we have n rows of m points, which gives
(n-1) * (m-1) rectangles. Among these, only (n-3) * (m-3)
rectangles will be approximated. We consider each of these
rectangles to be divided into M x N tiny rectangles, which we
will call 'elements'. There will be A points in the output file
for each horizontal grid line: */
A = (m-3) * M+1;
printf ("
i
j\n");
for (i = 2; i <= n-2; i++)
for (j = 2; j <= m-2; j++)
{
h11 = (i-1) * m+j;
h10 = h11-1; h12 = h10+2; h13 = h10+3;
h00 = h10-m; h01 = h00+1; h02 = h00+2; h03 = h00+3;
h20 = h10+m; h21 = h20+1; h22 = h20+2; h23 = h20+3;
h30 = h20+m; h31 = h30+1; h32 = h30+2; h33 = h30+3;
printf("%3d %3d\n", i,
j); /* Show that we are busy */
/* Here the 16 points are numbered as follows:
P00 P01 P02 P03
P10 P11 P12 P13
P20 P21 P22 P23
P30 P31 P32 P33
The inner region, within P11, P12, P21, P22, will be
approximated in this step (with the current values of
i and j ).
*/
x00 = xx[h00]; y00 = yy[h00]; z00 = zz[h00];
x01 = xx[h01]; y01 = yy[h01]; z01 = zz[h01];
x02 = xx[h02]; y02 = yy[h02]; z02 = zz[h02];
x03 = xx[h03]; y03 = yy[h03]; z03 = zz[h03];
x10 = xx[h10]; y10 = yy[h10]; z10 = zz[h10];
x11 = xx[h11]; y11 = yy[h11]; z11 = zz[h11];
x12 = xx[h12]; y12 = yy[h12]; z12 = zz[h12];
x13 = xx[h13]; y13 = yy[h13]; z13 = zz[h13];
81
x20 = xx[h20]; y20 = yy[h20]; z20 = zz[h20];
x21 = xx[h21]; y21 = yy[h21]; z21 = zz[h21];
x22 = xx[h22]; y22 = yy[h22]; z22 = zz[h22];
x23 = xx[h23]; y23 = yy[h23]; z23 = zz[h23];
x30 = xx[h30]; y30 = yy[h30]; z30 = zz[h30];
x31 = xx[h31]; y31 = yy[h31]; z31 = zz[h31];
x32 = xx[h32]; y32 = yy[h32]; z32 = zz[h32];
x33 = xx[h33]; y33 = yy[h33]; z33 = zz[h33];
a33 = (x00-x03-x30+x33+3*(-x01+x02-x10+x13+x20-x23+x31-x32)
+ 9*(x11-x12-x21+x22))/36;
a32 = (-x00-x02+x30+x32 + 2*(x01-x31) + 3*(x10+x12-x20-x22)
+ 6*(-x11+x21))/12;
a31 = (x00-x02-x30+x32 + 3*(-x10+x12+x20-x22))/12;
a30 = (-x00-x02+x30+x32 + 3*(x10+x12-x20-x22) + 4*(-x01+x31)
+ 12*(x11-x21))/36;
a23 = (-x00+x03-x20+x23 + 2*(x10-x13) + 3*(x01-x02+x21-x22)
+ 6*(x12-x11))/12;
a22 = (x00+x02+x20+x22 + 2*(-x01-x10-x12-x21))/4 + x11;
a21 = (x02-x00-x20+x22 + 2*(x10-x12))/4;
a20 = (x00+x02+x20+x22 - 2*(x10+x12)+ 4*(x01+x21) - 8*x11)/12;
a13 = (x00-x03-x20+x23 + 3*(x02-x01+x21-x22))/12;
a12 = (-x00-x02+x20+x22 + 2*(x01-x21))/4;
a11 = (x00-x02-x20+x22)/4;
a10 = (-x00-x02+x20+x22 + 4*(-x01+x21))/12;
a03 = (x03-x00-x20+x23 + 3*(x01-x02+x21-x22) + 4*(x13-x10)
+ 12*(x11-x12))/36;
a02 = (x00+x02+x20+x22 - 2*(x01+x21) + 4*(x10+x12) - 8*x11)/12;
a01 = (x02-x00-x20+x22 + 4*(x12-x10))/12;
a00 = (x00+x02+x20+x22 + 4*(x01+x10+x12+x21)+ 16*x11)/36;
b33 = (y00-y03-y30+y33 + 3*(-y01+y02-y10+y13+y20-y23+y31-y32)
+9*(y11-y12-y21+y22))/36;
b32 = (-y00-y02+y30+y32 + 2*(y01-y31)+ 3*(y10+y12-y20-y22) +
6*(-y11+y21))/12;
b31 = (y00-y02-y30+y32 + 3*(-y10+y12+y20-y22))/12;
b30 = (-y00-y02+y30+y32 + 3*(y10+y12-y20-y22) + 4*(-y01+y31)
+ 12*(y11-y21))/36;
b23 = (-y00+y03-y20+y23 + 2*(y10-y13)+ 3*(y01-y02+y21-y22) +
6*(y12-y11))/12;
b22 = (y00+y02+y20+y22 + 2*(-y01-y10-y12-y21))/4 + y11;
b21 = (y02-y00-y20+y22 + 2*(y10-y12))/4;
82
b20 = (y00+y02+y20+y22 - 2*(y10+y12) + 4*(y01+y21) - 8*y11)/12;
b13 = (y00-y03-y20+y23 + 3*(y02-y01+y21-y22))/12;
b12 = (-y00-y02+y20+y22 + 2*(y01-y21))/4;
b11 = (y00-y02-y20+y22)/4;
b10 = (-y00-y02+y20+y22 + 4*(-y01+y21))/12;
b03 = (y03-y00-y20+y23 + 3*(y01-y02+y21-y22) + 4*(y13-y10)
+ 12*(y11-y12))/36;
b02 = (y00+y02+y20+y22 - 2*(y01+y21) + 4*(y10+y12) - 8*y11)/12;
b01 = (y02-y00-y20+y22 + 4*(y12-y10))/12;
b00 = (y00+y02+y20+y22 + 4*(y01+y10+y12+y21) + 16*y11)/36;
c33 = (z00-z03-z30+z33 + 3*(-z01+z02-z10+z13+z20-z23+z31-z32)
+9*(z11-z12-z21+z22))/36;
c32 = (-z00-z02+z30+z32 + 2*(z01-z31) + 3*(z10+z12-z20-z22) +
6*(-z11+z21))/12;
c31 = (z00-z02-z30+z32 + 3*(-z10+z12+z20-z22))/12;
c30 = (-z00-z02+z30+z32 + 3*(z10+z12-z20-z22)+ 4*(-z01+z31)
+ 12*(z11-z21))/36;
c23 = (-z00+z03-z20+z23 + 2*(z10-z13)+ 3*(z01-z02+z21-z22)
+ 6*(z12-z11))/12;
c22 = (z00+z02+z20+z22 + 2*(-z01-z10-z12-z21))/4 + z11;
c21 = (z02-z00-z20+z22 + 2*(z10-z12))/4;
c20 = (z00+z02+z20+z22 - 2*(z10+z12) + 4*(z01+z21) - 8*z11)/12;
c13 = (z00-z03-z20+z23 + 3*(z02-z01+z21-z22))/12;
c12 = (-z00-z02+z20+z22 + 2*(z01-z21))/4;
c11 = (z00-z02-z20+z22)/4;
c10 = (-z00-z02+z20+z22 + 4*(-z01+z21))/12;
c03 = (z03-z00-z20+z23 + 3*(z01-z02+z21-z22)+ 4*(z13-z10)
+ 12*(z11-z12))/36;
c02 = (z00+z02+z20+z22 - 2*(z01+z21) + 4*(z10+z12) - 8*z11)/12;
c01 = (z02-z00-z20+z22 + 4*(z12-z10))/12;
c00 = (z00+z02+z20+z22 + 4*(z01+z10+z12+z21) + 16*z11)/36;
/* In the output file we will be using point numbers k,
which are to be computed from the controlled variables i, j,
I, J. In each rectangle, determined by the pair (i, j) and
to be divided into N x M elements, we use I, counting up to
N, and J, counting up to M. To avoid duplicated points, I
and J normally start at I, except for the lowest values (2)
of i and j; then I and J start at 0, respectively.
(Of all rectangles that are to be divided into elements,
the one with i=j=2 is the leftmost rectangle at the top.)
83
If I=0 (which implies i=2), then k = (j-2)M+J+1, otherwise
k = A+ (i-2)NA + (I-1)A + (j-2)M + J+ 1.
This means that in either case we have:
k = {(i-2)N + I}A + {(j-2)M +1}+J
(A is the total number of mesh points on a horizontal row. )
*/
B = (j-2)*M+1;
for (I = (i == 2 ? 0 : 1);I <= N; I++)
{
u = float(I)/N; u2 = u*u; u3 = u2*u;
C = ((i-2)*N+I)*A + B;
for (J = (j == 2 ? 0: 1); J <= M; J++)
{
k = C + J;
v = float(J)/M;
x = a03*v+a02)*v+a01)*v+a00+u*(((a13*v+a12)*v+a11)*v+a10)
+u2*(((a23*v+a22)*v+a21)*v+a20)+u3*(((a33*v+a32)*v+a31)*v+a30);
y = ((b03*v+b02)*v+b01)*v+b00+u*(((b13*v+b12)*v+b11)*v+b10)+
u2*(((b23*v+b22)*v+b21)*v+b20)+u3*(((b33*v+b32)*v+b31)*v+b30);
z = ((c03*v+c02)*v+c01)*v+c00+u*(((c13*v+c12)*v+c11)*v+c10)+
u2*(((c23*v+c22)*v+c21)*v+c20)+u3*(((c33*v+c32) *v+c31)*v+c30);
fprintf(fp2, "%d %f %f %f\n", k, x, y, z);
}
}
}
fprintf ( fp2, "Faces: \n" );
nn = (n-3) * N;
mm = A-1;
/* mm = (m-3)*M */
for (ii = 0; ii < nn; ii++)
for (jj = 0; jj < mm; jj++)
{
P = ii * A + jj + 1;
/* We have to divide each (nearly rectangular) surface
element into two triangles to ensure that the points
that will be used as vertices of polygons really lie
in the same plane. The minus sign in, for example,
p -Q R will prevent D3D from drawing line segment PQ.
Since either face of each triangle may be visible, we
specify its vertices both counter-clockwise and clockwise:
*/
84
fprintf(fp2, "%d %d %d#\n", P, -(P+A+1), P+1);
fprintf(fp2, "%d %d %d#\n", P+A+1, -P, P+A);
fprintf(fp2, "%d %d %d#\n", P, -(P+A+1), P+A);
fprintf(fp2, "%d %d %d#\n", P+A+1, -P, P+1);
}
fclose(fp2);
}
/* BSPLSURF: B-spline surface.
This program expects a D3D object, file in which a grid of points is
defined. The program asks the user to enter m and n: there must be
exactly mn points in the file, numbered 1, 2, ..., mn. It is assumed
that these points are arranged in a grid as follows:
1
2
...
m
m+1
m+2
...
2m
2m+1
2m+2
...
3m
.
.
.
.
(n-l)m+1 (n-1)+2
...
mn
Neither m nor n must be less than 4. The position of the points in 3D
space is free: no two points need have the same x-, y-, or z-coordinates.
If the object file contains a section beginning with "Faces:", then this
section is ignored. Two integers M and N are to be entered; they denote
numbers of intervals used in the surface-fitting process. There will be
M intervals between the points 1 and 2, and N intervals between the points
1 and m+1, and so on. The B-spline curved surface that approximates the
given points is written to an output file in D3D format.
*/
#include <stdio.h>
#include <process.h>
#define Horner(t, a3, a2, a1, a0)
((((a3)*(t)+(a2))*(t)+(a1))*(t)+(a0))
typedef struct Point3Struct {float x, y, z; } Point3;
typedef float Coef;
typedef int Index;
void main()
{
FILE *fp1, *fp2;
char str[30] ;
Point3 *Q, T, P[4][4];
85
float v, u, u2, u3, a[4][4], b[4][4], c[4][4];
Index i, j, k, r, c1, I, J, ii, jj;
int
do
{
m, n, M, N, mn, A, B, C, nn, mm, p, h[4][4];
printf ("Enter m and n (both at least 4): ");
scanf ("%d %d", &m, &n);
} while (m < 4 || n < 4);
printf ("Input file:
"); scanf("%s", str);
fp1 = fopen (str, "r");
printf ("Output file: "); scanf("%s", str);
fp2 = fopen (str, "w");
if (fp1 == NULL || fp2 == NULL)
{
printf ("File problem"); exit(1); }
mn = m * n;
Q = new Point3[mn+1];
// Point3 Q[mn+1]
for (i = 0; i < mn; i++)
{
if (fscanf(fp1, "%d %f %f %f", &k, &(T.x), &(T.y), &(T.z)) != 4)
{
printf ("Too few points in file"); exit (1);
}
if (k < 1 || k > mn)
{ printf ("Point number %d incorrect", k); exit(1);
Q[k].x = T.x; Q[k].y = T.y; Q[k].z = T.z;
}
}
fclose(fp1);
printf ("Enter M and N: "); scanf("%d %d", &M, &N);
/*
Let us imagine that we have n rows of m points, which gives
(n-1) * (m-1) rectangles. Among these, only (n-3) * (m-3)
rectangles will be approximated. We consider each of these
rectangles to be divided into M x N tiny rectangles, which we
will call 'elements'. There will be A points in the output file
for each horizontal grid line: */
A = (m-3) * M+1;
printf (" i j\n");
for (i = 2; i <= n-2; i++)
for (j = 2; j <= m-2; j++)
{
h[1][1] = (i-1) * m+j;
h[1][0] = h[1][1]-1; h[1][2] = h[1][0]+2; h[1][3] = h[1][0]+3;
86
h[0][0] = h[1][0]-m; h[0][1] = h[0][0]+1; h[0][2] = h[0][0]+2;
h[0][3] = h[0][0]+3;
h[2][0] = h[1][0]+m; h[2][1] = h[2][0]+1; h[2][2] = h[2][0]+2;
h[2][3] = h[2][0]+3;
h[3][0] = h[2][0]+m; h[3][1] = h[3][0]+1; h[3][2] = h[3][0]+2;
h[3][3] = h[3][0]+3;
printf("%3d %3d\n", i, j); /* Show that we are busy */
/* Here the 16 points are numbered as follows:
P00 P01 P02 P03
P10 P11 P12 P13
P20 P21 P22 P23
P30 P31 P32 P33
The inner region, within P11, P12, P21, P22, will be
approximated in this step (with the current values of
i and j ). */
for (r = 0; r < 4; r++)
for (c1 = 0; c1 < 4; c1++)
P[r][c1] = Q[h[r][c1]];
a[3][3] = (P[0][0].x-P[0][3].x-P[3][0].x+P[3][3].x+
3*(-P[0][1].x+P[0][2].x-P[1][0].x+P[1][3].x+P[2][0].x
-P[2][3].x+P[3][1].x-P[3][2].x) + 9*(P[1][1].x-P[1][2].xP[2][1].x+P[2][2].x))/36;
a[3][2] = (-P[0][0].x-P[0][2].x+P[3][0].x+P[3][2].x + 2*(P[0][1].x-P[3][1].x)
+ 3*(P[1][0].x+P[1][2].x-P[2][0].x-P[2][2].x) +
6*(-P[1][1].x+P[2][1].x))/12;
a[3][1] = (P[0][0].x-P[0][2].x-P[3][0].x+P[3][2].x + 3*(-P[1][0].x+
P[1][2].x+P[2][0].x-P[2][2].x))/12;
a[3][0] = (-P[0][0].x-P[0][2].x+P[3][0].x+P[3][2].x + 3*(P[1][0].x+
P[1][2].x-P[2][0].x-P[2][2].x) + 4*(-P[0][1].x+P[3][1].x)
+ 12*(P[1][1].x-P[2][1].x))/36;
a[2][3] = (-P[0][0].x+P[0][3].x-P[2][0].x+P[2][3].x + 2*(P[1][0].x-P[1][3].x) +
3*(P[0][1].x-P[0][2].x+P[2][1].x-P[2][2].x) +
6*(P[1][2].x-P[1][1].x))/12;
a[2][2] = (P[0][0].x+P[0][2].x+P[2][0].x+P[2][2].x +
2*(-P[0][1].x-P[1][0].x-P[1][2].x-P[2][1].x))/4 + P[1][1].x;
a[2][1] = (P[0][2].x-P[0][0].x-P[2][0].x+P[2][2].x
+ 2*(P[1][0].x-P[1][2].x))/4;
a[2][0] = (P[0][0].x+P[0][2].x+P[2][0].x+P[2][2].x - 2*(P[1][0].x+P[1][2].x)+
4*(P[0][1].x+P[2][1].x) - 8*P[1][1].x)/12;
a[1][3] = (P[0][0].x-P[0][3].x-P[2][0].x+P[2][3].x +
3*(P[0][2].x-P[0][1].x+P[2][1].x-P[2][2].x))/12;
87
a[1][2] = (-P[0][0].x-P[0][2].x+P[2][0].x+P[2][2].x +
2*(P[0][1].x-P[2][1].x))/4;
a[1][1] = (P[0][0].x-P[0][2].x-P[2][0].x+P[2][2].x)/4;
a[1][0] = (-P[0][0].x-P[0][2].x+P[2][0].x+P[2][2].x +
4*(-P[0][1].x+P[2][1].x))/12;
a[0][3] = (P[0][3].x-P[0][0].x-P[2][0].x+P[2][3].x +
3*(P[0][1].x-P[0][2].x+P[2][1].x-P[2][2].x) +
4*(P[1][3].x-P[1][0].x) + 12*(P[1][1].x-P[1][2].x))/36;
a[0][2] = (P[0][0].x+P[0][2].x+P[2][0].x+P[2][2].x 2*(P[0][1].x+P[2][1].x) + 4*(P[1][0].x+P[1][2].x) 8*P[1][1].x)/12;
a[0][1] = (P[0][2].x-P[0][0].x-P[2][0].x+P[2][2].x +
4*(P[1][2].x-P[1][0].x))/12;
a[0][0] = (P[0][0].x+P[0][2].x+P[2][0].x+P[2][2].x + 4*(P[0][1].x +
P[1][0].x+P[1][2].x+P[2][1].x)+ 16*P[1][1].x)/36;
b[3][3] = (P[0][0].y-P[0][3].y-P[3][0].y+P[3][3].y +
3*(-P[0][1].y+P[0][2].y-P[1][0].y+P[1][3].y+
P[2][0].y-P[2][3].y+P[3][1].y-P[3][2].y) +
9*(P[1][1].y-P[1][2].y-P[2][1].y+P[2][2].y))/36;
b[3][2] = (-P[0][0].y-P[0][2].y+P[3][0].y+P[3][2].y + 2*(P[0][1].y-P[3][1].y)
+ 3*(P[1][0].y+P[1][2].y-P[2][0].y-P[2][2].y) +
6*(-P[1][1].y+P[2][1].y))/12;
b[3][1] = (P[0][0].y-P[0][2].y-P[3][0].y+P[3][2].y +
3*(-P[1][0].y+P[1][2].y+P[2][0].y-P[2][2].y))/12;
b[3][0] = (-P[0][0].y-P[0][2].y+P[3][0].y+P[3][2].y +
3*(P[1][0].y+P[1][2].y-P[2][0].y-P[2][2].y) +
4*(-P[0][1].y+P[3][1].y)+12*(P[1][1].y-P[2][1].y))/36;
b[2][3] = (-P[0][0].y+P[0][3].y-P[2][0].y+P[2][3].y + 2*(P[1][0].y-P[1][3].y)+
3*(P[0][1].y-P[0][2].y+P[2][1].y-P[2][2].y) +
6*(P[1][2].y-P[1][1].y))/12;
b[2][2] = (P[0][0].y+P[0][2].y+P[2][0].y+P[2][2].y +
2*(-P[0][1].y-P[1][0].y-P[1][2].y-P[2][1].y))/4 + P[1][1].y;
b[2][1] = (P[0][2].y-P[0][0].y-P[2][0].y+P[2][2].y +
2*(P[1][0].y-P[1][2].y))/4;
b[2][0] = (P[0][0].y+P[0][2].y+P[2][0].y+P[2][2].y 2*(P[1][0].y+P[1][2].y) + 4*(P[0][1].y+P[2][1].y) 8*P[1][1].y)/12;
b[1][3] = (P[0][0].y-P[0][3].y-P[2][0].y+P[2][3].y +
3*(P[0][2].y-P[0][1].y+P[2][1].y-P[2][2].y))/12;
b[1][2] = (-P[0][0].y-P[0][2].y+P[2][0].y+P[2][2].y +
88
2*(P[0][1].y-P[2][1].y))/4;
b[1][1] = (P[0][0].y-P[0][2].y-P[2][0].y+P[2][2].y)/4;
b[1][0] = (-P[0][0].y-P[0][2].y+P[2][0].y+P[2][2].y +
4*(-P[0][1].y+P[2][1].y))/12;
b[0][3] = (P[0][3].y-P[0][0].y-P[2][0].y+P[2][3].y +
3*(P[0][1].y-P[0][2].y+P[2][1].y-P[2][2].y) +
4*(P[1][3].y-P[1][0].y)+12*(P[1][1].y-P[1][2].y))/36;
b[0][2] = (P[0][0].y+P[0][2].y+P[2][0].y+P[2][2].y 2*(P[0][1].y+P[2][1].y) + 4*(P[1][0].y+P[1][2].y) 8*P[1][1].y)/12;
b[0][1] = (P[0][2].y-P[0][0].y-P[2][0].y+P[2][2].y +
4*(P[1][2].y-P[1][0].y))/12;
b[0][0] = (P[0][0].y+P[0][2].y+P[2][0].y+P[2][2].y +
4*(P[0][1].y+P[1][0].y+P[1][2].y+P[2][1].y) +
16*P[1][1].y)/36;
c[3][3] = (P[0][0].z-P[0][3].z-P[3][0].z+P[3][3].z +
3*(-P[0][1].z+P[0][2].z-P[1][0].z+P[1][3].z+P[2][0].zP[2][3].z+P[3][1].z-P[3][2].z) +
9*(P[1][1].z-P[1][2].z-P[2][1].z+P[2][2].z))/36;
c[3][2] = (-P[0][0].z-P[0][2].z+P[3][0].z+P[3][2].z +
2*(P[0][1].z-P[3][1].z) + 3*(P[1][0].z+P[1][2].z-P[2][0].zP[2][2].z) + 6*(-P[1][1].z+P[2][1].z))/12;
c[3][1] = (P[0][0].z-P[0][2].z-P[3][0].z+P[3][2].z +
3*(-P[1][0].z+P[1][2].z+P[2][0].z-P[2][2].z))/12;
c[3][0] = (-P[0][0].z-P[0][2].z+P[3][0].z+P[3][2].z +
3*(P[1][0].z+P[1][2].z-P[2][0].z-P[2][2].z)+
4*(-P[0][1].z+P[3][1].z) + 12*(P[1][1].z-P[2][1].z))/36;
c[2][3] = (-P[0][0].z+P[0][3].z-P[2][0].z+P[2][3].z +
2*(P[1][0].z-P[1][3].z)+ 3*(P[0][1].z-P[0][2].z+P[2][1].zP[2][2].z) + 6*(P[1][2].z-P[1][1].z))/12;
c[2][2] = (P[0][0].z+P[0][2].z+P[2][0].z+P[2][2].z + 2*(-P[0][1].zP[1][0].z-P[1][2].z-P[2][1].z))/4 + P[1][1].z;
c[2][1] = (P[0][2].z-P[0][0].z-P[2][0].z+P[2][2].z +
2*(P[1][0].z-P[1][2].z))/4;
c[2][0] = (P[0][0].z+P[0][2].z+P[2][0].z+P[2][2].z 2*(P[1][0].z+P[1][2].z) + 4*(P[0][1].z+P[2][1].z) 8*P[1][1].z)/12;
c[1][3] = (P[0][0].z-P[0][3].z-P[2][0].z+P[2][3].z +
3*(P[0][2].z-P[0][1].z+P[2][1].z-P[2][2].z))/12;
c[1][2] = (-P[0][0].z-P[0][2].z+P[2][0].z+P[2][2].z +
89
2*(P[0][1].z-P[2][1].z))/4;
c[1][1] = (P[0][0].z-P[0][2].z-P[2][0].z+P[2][2].z)/4;
c[1][0] = (-P[0][0].z-P[0][2].z+P[2][0].z+P[2][2].z +
4*(-P[0][1].z+P[2][1].z))/12;
c[0][3] = (P[0][3].z-P[0][0].z-P[2][0].z+P[2][3].z +
3*(P[0][1].z-P[0][2].z+P[2][1].z-P[2][2].z)+
4*(P[1][3].z-P[1][0].z)+12*(P[1][1].z-P[1][2].z))/36;
c[0][2] = (P[0][0].z+P[0][2].z+P[2][0].z+P[2][2].z 2*(P[0][1].z+P[2][1].z) + 4*(P[1][0].z+P[1][2].z) 8*P[1][1].z)/12;
c[0][1] = (P[0][2].z-P[0][0].z-P[2][0].z+P[2][2].z +
4*(P[1][2].z-P[1][0].z))/12;
c[0][0] = (P[0][0].z+P[0][2].z+P[2][0].z+P[2][2].z +
4*(P[0][1].z+P[1][0].z+P[1][2].z+P[2][1].z) +
16*P[1][1].z)/36;
/* In the output file we will be using point numbers k,
which are to be computed from the controlled variables i, j,
I, J. In each rectangle, determined by the pair (i, j) and
to be divided into N x M elements, we use I, counting up to
N, and J, counting up to M. To avoid duplicated points, I
and J normally start at I, except for the lowest values (2)
of i and j; then I and J start at 0, respectively.
(Of all rectangles that are to be divided into elements,
the one with i=j=2 is the leftmost rectangle at the top.)
If I=0 (which implies i=2), then k = (j-2)M+J+1, otherwise
k = A+ (i-2)NA + (I-1)A + (j-2)M + J+ 1.
This means that in either case we have:
k = {(i-2)N + I}A + {(j-2)M +1}+J
(A is the total number of mesh points on a horizontal row. )
*/
B = (j-2)*M+1;
for (I = (i == 2 ? 0 : 1);I <= N; I++)
{
u = float(I)/N; u2 = u*u; u3 = u2*u;
C = ((i-2)*N+I)*A + B;
for (J = (j == 2 ? 0: 1); J <= M; J++)
{
k = C + J;
v = float(J)/M;
T.x = Horner(v, a[0][3], a[0][2], a[0][1], a[0][0]) +
90
u * Horner(v, a[1][3], a[1][2], a[1][1], a[1][0])+
u2 * Horner(v, a[2][3], a[2][2], a[2][1], a[2][0])+
u3 * Horner(v, a[3][3], a[3][2], a[3][1], a[3][0]);
T.y = Horner(v, b[0][3], b[0][2], b[0][1], b[0][0]) +
u * Horner(v, b[1][3], b[1][2], b[1][1], b[1][0])+
u2 * Horner(v, b[2][3], b[2][2], b[2][1], b[2][0])+
u3 * Horner(v, b[3][3], b[3][2], b[3][1], b[3][0]);
T.z = Horner(v, c[0][3], c[0][2], c[0][1], c[0][0]) +
u * Horner(v, c[1][3], c[1][2], c[1][1], c[1][0])+
u2 * Horner(v, c[2][3], c[2][2], c[2][1], c[2][0])+
u3 * Horner(v, c[3][3], c[3][2], c[3][1], c[3][0]);
fprintf(fp2, "%d %f %f %f\n", k, T.x, T.y, T.z);
}
}
}
fprintf ( fp2, "Faces: \n" );
nn = (n-3) * N;
mm = A-1;
/* mm = (m-3)*M */
for (ii = 0; ii < nn; ii++)
for (jj = 0; jj < mm; jj++)
{
p = ii * A + jj + 1;
/* We have to divide each (nearly rectangular) surface
element into two triangles to ensure that the points
that will be used as vertices of polygons really lie
in the same plane. The minus sign in, for example,
p -Q R will prevent D3D from drawing line segment PQ.
Since either face of each triangle may be visible, we
specify its vertices both counter-clockwise and clockwise:
*/
fprintf(fp2, "%d %d %d#\n", p, -(p+A+1), p+1);
fprintf(fp2, "%d %d %d#\n", p+A+1, -p, p+A);
fprintf(fp2, "%d %d %d#\n", p, -(p+A+1), p+A);
fprintf(fp2, "%d %d %d#\n", p+A+1, -p, p+1);
}
fclose(fp2);
}
91
參考文獻:
1. L. Ammeraal, Programming Principles in Computer Graphics, John Wiley & Sons, 1986.
2. L. Ammeraal, Interactive 3D Computer Graphics, John Wiley & Sons, 19886.
92
Download