#define PROG_NAME "Halo" #define PROG_DESC "???" #define PROG_VERS "1.0" #define Halo_C_COPYRIGHT \ "" #define PROG_INFO \ "" \ " " /* This program implements the "Atmospheric effect" technique. If we only render nodes, @{edge->?}s, and walls of the 3D model, ignoring the cells, we will get a rather incomplete, ``paper frame'' view of the 3-map---just as incomplete as a wireframe view of a triangle mesh. To complete the picture, we should make the cells themselves visible, by filling them with some semitransparent participating medium ---such as fog, rain, colored liquid, neon glow, etc. Notice: Run the results of this module with the POVRay code in /n/lac/pkg/povray-3.1a-1/PUB/sun4-SunOS-5.5 */ #include #include #include #include #define _GNU_SOURCE #include #include #include #include #include #include #include #include CONST double Epsilon = 0.0000000001; VAR Wa,Wb,Wc,Wd : r4_t; /* [[!!! DOES THIS COMMENT FROM Octf.h APPLY HERE ??? */ /* A '@{chip->?}' is a group of four @places, consisting of two mutually dual wedges. */ TYPE double FourNodes_t = RECORD u, v, w, x: uint; } typedef struct Options_t { char *inFileTp; char *inFileSt; char *outFile; char *projectionName; bool_t autoProject; double normalize; /* Normalize al nodes onto the S^3 with that radius.*/ From4: r4_t; /* */ To4: r4_t; /* 4D viewing parameters as expected by the */ Up4: r4_t; /* "Wire4"- Interactive 4D Wireframe Display */ Over4: r4_t; /* Program. */ Vangle4: double; /* */ bool_t silhouette; /* TRUE draws the silhouette walls */ bool_t filter; /* TRUE uses filtered colors, FALSE transmit colors. */ color: frgb_t; /* attributes of color and opacity for silhouette */ REAL opacity; /* walls,Transparent (opacity==1) Opaque (opacity==1)*/ bool_t all; /* drawing all nodes and edges */ uint cell; } PROCEDURE WL(double x) : char *== { return(Fmt.Pad(Fmt.LongReal(x, Fmt.Style.Fix, prec = 2), 6)); } /* END WL */ bool_t Sign(d: double) /* Return TRUE iff the longreal value is positive, FALSE c.c. */ { assert(d!=0.0); if (d < 0.0){ return FALSE }else{ return TRUE; }; } /* END Sign */ Options_t *GetOptions(int argc, char **argv); int main(int argc, char **argv) Options_t *o = GetOptions(argc, argv); char *topo_cmt = jsprintf("Created by %s on %s", PROG_NAME, Today()); /* Random_t coins = MakeRandomSource(4615); */ char *newcmt; { ??? tc = Triangulation.ReadToTaMa(o->inFileTp); ??? top = tc.top; ??? rc = Triangulation.ReadState(o->inFileSt); ??? c = rc^; ??? rc3 = NEW(REF Tridimensional.Coord3D; with (top->node.nel), double c3 = rc3^; double rdepth = double_vec_new(top->node.nel); double depth = rdepth^; double cmt = tc.cmt & "\nProjected in " & o->projectionName \ ": " & o->outFile & ".st3 on " & Today() ){ if (o->normalize > 0.0) { fprintf(stderr, "projecting nodes onto the unit S^3\n"); NormalizeNodeCoords(c, o->normalize); } if (o->autoProject ){ SelectProjection(o, c, top); newcmt = cmt & "\nWith AutoProject"; } else { newcmt = cmt & "\nParameters: " \ "\nFrom4: " & WL(o->From4[0]) & WL(o->From4[1]) & WL(o->From4[2]) & WL(o->From4[3]) \ "\nTo4: " & WL(o->To4[0]) & WL(o->To4[1]) & WL(o->To4[2]) & WL(o->To4[3]) \ "\nUp4: " & WL(o->Up4[0]) & WL(o->Up4[1]) & WL(o->Up4[2]) & WL(o->Up4[3]) \ "\nOver4: " & WL(o->Over4[0]) & WL(o->Over4[1]) & WL(o->Over4[2]) & WL(o->Over4[3]) \ "\nVangle4: " & WL(o->Vangle4); } ProjectTo3D(o, c, c3, depth, top); WritePOVFile(o->outFile&"-"&Fmt.Int(o->cell), top, c3, o); return 0; } void NormalizeNodeCoords(VAR c: Coords_t; newR: double) { ??? b = Barycenter(c); { for (i = 0 TO (c.nel-1)) { ??? p = c[i], q == r4_Sub(p, b), r == r4_Norm(q); { if (r > 0.0){ p = r4_Scale(newR/r, q);} } } } } NormalizeNodeCoords; r4_t Barycenter(*c: Coords_t) r4_t B = (r4_t){0.0, ..}; VAR { for (i = 0 TO (c.nel-1)){ B = r4_Add(B, c[i]); } return r4_Scale(1.0/FLOAT((c.nel), double), B); } Barycenter; void CalcV4Matrix(*o: Options_t) /* This procedure computes the four basis vectors for the 4D viewing matrix, Wa,Wb,Wc, and Wd. Note that the Up vector transforms to Wb, the Over vector transforms to Wc, and the line of sight transforms to Wd. The Wa vector is then computed from Wb,Wc and Wd. */ VAR double norm; { /* Calculate Wd, the 4th coordinate basis vector and line-of-sight. */ Wd = r4_Sub(o->To4,o->From4); norm = r4_Norm(Wd); if (norm < Epsilon) { fprintf(stderr,"4D To Point and From Point are the same\n"); Process.Exit¦(1); } Wd = r4_Scale(1.0/norm, Wd); /* Calculate Wa, the X-axis basis vector. */ Wa = r4_cross(o->Up4,o->Over4,Wd); norm = r4_Norm(Wa); if (norm < Epsilon) { fprintf(stderr, "4D up,over and view vectors are not perpendicular\n"); Process.Exit¦(1); } Wa = r4_Scale(1.0/norm, Wa); /* Calculate Wb, the perpendicularized Up vector. */ Wb = r4_cross(o->Over4,Wd,Wa); norm = r4_Norm(Wb); if (norm < Epsilon) { fprintf(stderr,"Invalid 4D over vector\n"); Process.Exit¦(1); } Wb = r4_Scale(1.0/norm, Wb); /* Calculate Wc, the perpendicularized Over vector. Note that the resulting vector is already normalized, since Wa, Wb and Wd are all unit vectors. */ Wc = r4_cross(Wd,Wa,Wb); } CalcV4Matrix; PROCEDURE ProjectTo3D( Options_t *o = (Options_t *)malloc(sizeof(Options_t)); Coords_t *c; VAR c3: Tridimensional.Coord3D; double_vec_t depth, ElemTableRec_t *top) VAR Tan2Vangle4, Data4Radius, pconst, rtemp: double; TempV : r4_t; { ??? angle = o->Vangle4/2.0; ??? angler = (FLOAT(Math.Pi, double)*angle)/180.0); with( ) { Tan2Vangle4 = Math.tan(angler); } /* Find the radius of the 4D data. The radius of the 4D data is the radius of the smallest enclosing sphere, centered at the To point. Note that during the loop through the nodes, Data4Radius holds the squared radius value. */ Data4Radius = 0.0; for (i = 0; i < top->node.nel; i++) { Node_t v = OrgV(top->node.el[i]); ??? Temp4 = r4_Sub(c[v->num]; with (o->To4), double dist = r4_dot(Temp4,Temp4) ){ if (dist > Data4Radius) { Data4Radius = dist; } } } Data4Radius = sqrt(Data4Radius); fprintf(stderr,"Data4Radius: "& Fmt.Pad(Fmt.LongReal(Data4Radius, Fmt.Style.Fix, prec = 4),8)&"\n\n"); CalcV4Matrix(o); if (0 == strcmp(o->projectionName, "Parallel"))) { rtemp = 1.0 / Data4Radius; } else { pconst = 1.0 / Tan2Vangle4; } for (i = 0; i < top->node.nel; i++) { /* Transform the nodes from 4D World coordinates to 4D eye coordinates. */ Node_t v = OrgV(top->node.el[i]); { TempV = r4_Sub(c[v->num],o->From4); depth[v->num] = r4_dot(TempV,Wd); if (0 == strcmp(o->projectionName, "Perspective"))) { rtemp = pconst / depth[v->num]; } c3[v->num][0] = rtemp * r4_dot(TempV, Wa); c3[v->num][1] = rtemp * r4_dot(TempV, Wb); c3[v->num][2] = rtemp * r4_dot(TempV, Wc); } } } /* END ProjectTo3D */ PROCEDURE TetrahedronNodes(f:TriangulationPlace_t): ARRAY [0..3] OF uint { Place_t g = Tors(f); Place_t h = Tors(Clock(PrevE(f))); Node_t p = OrgV(g)->num; Node_t q = OrgV(NextE(g))->num; Node_t r = OrgV(PrevE(g))->num; Node_t s = OrgV(PrevE(h))->num; { return ARRAY [0..3] OF uint {p, q, r, s}; } } /* END TetrahedronNodes */ PROCEDURE SelectProjection( Options_t *o = (Options_t *)malloc(sizeof(Options_t)); Coords_t *c, ElemTableRec_t *top) norm: r4_t = (r4_t){0.0, ..}; { for (i = 0; i < top->cell.nel; i++){ ??? f = Srot(top.cell[i]); ??? k = TetrahedronNodes(f); ??? p = c[k[0]]; ??? q = c[k[1]]; ??? r = c[k[2]]; ??? s = c[k[3]]; ??? pq = r4_Sub(q; with ( p), double pr = r4_Sub(r, p); double ps = r4_Sub(s, p); double v = r4_cross(pq, pr, ps); double n = r4_Dir(v) ){ norm = r4_Add(norm, n) } } ??? m = r4_Norm(norm); { if (m < 1.0d-20) { norm = (r4_t){1.0, 0.0, ..} } else { norm = r4_Scale(1.0/m, norm) } } ??? bar = Triangulation.Barycenter(top; with ( c) ){ o->To4 = bar; o->From4 = r4_Add(o->To4, norm); SelectTwoIndepDirs(norm, o->Up4, o->Over4); o->Vangle4 = 120.0; } } /* END SelectProjection */ PROCEDURE SelectTwoIndepDirs( *u: r4_t; VAR v, w: r4_t; ) /* Selects two vectors "v", "w", independent of each other and of the given vector "u". */ m: uint = 0; { /* Find the largest coordinate of "u": */ for (i = 1; i < 4; i++){ if ((fabs(u[i]) > fabs(u[m]))){ m = i; } } for (i = 0; i < 4; i++){ v[i] = 0.0; w[i] = 0.0; } v[(m+1) % 4] = 1.0; w[(m+2) % 4] = 1.0; } /* END SelectTwoIndepDirs */ void WritePOVFile(char *name, *ElemTableRec_t *top; *c3: Tridimensional.Coord3D; Options_t *op; ) <* FATAL Wr.Failure, Thread.Alerted, OSError.E); { ??? wr = FileWr.Open(name & ".inc"); { fprintf(wr, "// Include File: <" & name & ".inc>\n"); WritePOV(wr, top, c3, op); fclose(wr) } } /* END WritePOVFile */ void WritePOV ( FILE *wr, *ElemTableRec_t *top; * c3: Coord3D; Options_t *o = (Options_t *)malloc(sizeof(Options_t)); ) == double FindOriR3(q: FourNodes_t) /* For each tetrahedron with extremus nodes numbers u,v,w,x computes its orientation in R^{3} through the 4x4 determinant: _ _ | c3[q.u][0] c3[q.u][1] c3[q.u][2] 1.0 | double B = | c3[q.v][0] c3[q.v][1] c3[q.v][2] 1.0 | | c3[q.w][0] c3[q.w][1] c3[q.w][2] 1.0 | | c3[q.x][0] c3[q.x][1] c3[q.x][2] 1.0 | - - */ { with ( double a = (r4_t){c3[q.u][0], c3[q.u][1], c3[q.u][2], 1.0}; double b = (r4_t){c3[q.v][0], c3[q.v][1], c3[q.v][2], 1.0}; double c = (r4_t){c3[q.w][0], c3[q.w][1], c3[q.w][2], 1.0}; double d = (r4_t){c3[q.x][0], c3[q.x][1], c3[q.x][2], 1.0} ){ return r4_det(a,b,c,d); } } FindOriR3; bool_t SilhouetteWalls(Place_t @p) /* Return TRUE iff the wall associated to the @place "a" is a silhouette wall, FALSE c.c. */ { ??? t = TetraNegPosNodes(a); ??? un = t[0]->num; ??? vn = t[1]->num; ??? wn = t[2]->num; ??? xn = t[3]->num; ??? yn = t[4]->num; with ( double t1 = FourNodes_t{un,vn,wn,xn}; double t2 = FourNodes_t{un,vn,wn,yn}; double d1 = FindOriR3(t1); double d2 = FindOriR3(t2) ){ if (((Sign(d1)) && (Sign(d2))) || (((NOT Sign(d1))) && ((NOT Sign(d2))))) { return TRUE; } else { return FALSE; } } } SilhouetteWalls; { /* drawing the edges */ for (i = 0; i < top->NE; i++) { ??? e = top->edge[i]; { if ((e->exists) || (o->all)) { ??? oo = e.node[0]->num; ??? d = e.node[1]->num; ??? t3 = e.transp; ??? transp = (t3[0] + t3[1] + t3[2]) / 3.0; { WritePOVCylinder(wr,c3[oo], c3[d], e.radius, e.color, transp, o->filter); } } } } /* drawing the nodes */ for (i = 0; i < top->node.nel; i++) { Node_t v = OrgV(top->node.el[i]); { if ((v->exists) || (o->all)) { ??? t3 = v.transp; ??? transp = (t3[0] + t3[1] + t3[2]) / 3.0; { WritePOVSphere(wr,c3[i], v.radius, v.color, transp, o->filter); } } } } for (i = 0; i < top->cell.nel; i++) { ??? r = Srot(top.cell[i]); Place_t a = Tors(r); ??? t = Triangulation.TetraNegNodes(a); ??? cun = c3[t[0]->num]; ??? cvn = c3[t[1]->num]; ??? cwn = c3[t[2]->num]; ??? cxn = c3[t[3]->num]; ??? color = top->cell[i].color; with ( double dwu = r3_sub(cwn,cun); double dvu = r3_sub(cvn,cun); double dxu = r3_sub(cxn,cun); double dwv = r3_sub(cwn,cvn); double dxv = r3_sub(cxn,cvn); nf0 == LR3Extras.Cross(dwu,dvu), double nf02 = LR3.Norm(nf0); nu0 == LR3.Dot(nf0,cun), nf1 == LR3Extras.Cross(dvu,dxu), double nf12 = LR3.Norm(nf1); nu1 == LR3.Dot(nf1,cun), nf2 == LR3Extras.Cross(dwv,dxv), double nf22 = LR3.Norm(nf2); nu2 == LR3.Dot(nf2,cvn), nf3 == LR3Extras.Cross(dxu,dwu), double nf32 = LR3.Norm(nf3); nu3 == LR3.Dot(nf3,cun), df0 == nu0/nf02, df1 == nu1/nf12, df2 == nu2/nf22, df3 == nu3/nf32 ){ CASE o->cell OF break; case 1: if ((color == (frgb_t){1.0,0.0,0.0})) { WritePOVTetrahedron(wr,nf0,nf1,nf2,nf3,df0,df1,df2,df3,color, 0.75, o->filter); } break; case 2: if ((color == (frgb_t){0.0,1.0,0.0})) { WritePOVTetrahedron(wr,nf0,nf1,nf2,nf3,df0,df1,df2,df3,color, 0.75,o->filter); } break; case 3: if ((color == (frgb_t){0.0,0.0,1.0})) { WritePOVTetrahedron(wr,nf0,nf1,nf2,nf3,df0,df1,df2,df3,color, 0.75,o->filter); } break; case 4: if ((color == (frgb_t){1.0,1.0,0.0})) { WritePOVTetrahedron(wr,nf0,nf1,nf2,nf3,df0,df1,df2,df3,color, 0.75,o->filter); } break; case 5: if ((color == (frgb_t){0.0,1.0,1.0})) { WritePOVTetrahedron(wr,nf0,nf1,nf2,nf3,df0,df1,df2,df3,color, 0.75,o->filter); } break; case 6: if ((color == (frgb_t){1.0,0.0,1.0})) { WritePOVTetrahedron(wr,nf0,nf1,nf2,nf3,df0,df1,df2,df3,color, 0.75,o->filter); } break; case 7: if ((color == (frgb_t){0.0,0.0,0.0})) { WritePOVTetrahedron(wr,nf0,nf1,nf2,nf3,df0,df1,df2,df3,color, 0.75,o->filter); } break; case 8: if ((color == (frgb_t){1.0,1.0,1.0})) { WritePOVTetrahedron(wr,nf0,nf1,nf2,nf3,df0,df1,df2,df3,color, 0.75,o->filter); } } else { /* nothing */ } } } if ((o->silhouette) && (top->der == 3)) { for (i = 0; i < top->wall.nel; i++) { ??? f = top->wall[i]; ??? a = f.pa; ??? un = f.node[0]->num; ??? vn = f.node[1]->num; ??? wn = f.node[2]->num; ??? c = o->color; ??? t = o->opacity; { if ((SilhouetteWalls(a)) && (NOT f->exists)) { WritePOVTriangle(wr,c3[un], c3[vn], c3[wn],c,t, o->filter); } } } } fflush(wr); } /* END WritePOV */ Options_t GetOptions () { Options_t *o = (Options_t *)malloc(sizeof(Options_t)); argparser_t *pp = argparser_new(stderr, argc, argv); argparser_set_help(pp, PROG_NAME " version " PROG_VERS ", usage:\n" PROG_HELP); argparser_set_info(pp, PROG_INFO); argparser_process_help_info_options(pp); argparser_get_keyword(pp, "-inFileTp"); o->inFileTp = argparser_get_next(pp); argparser_get_keyword(pp, "-inFileSt"); o->inFileSt = argparser_get_next(pp); if ((argparser_keyword_present(pp, "-outFile"))) { o->outFile = argparser_get_next(pp) } else { o->outFile = o->inFileTp } o->all = argparser_keyword_present(pp, "-all"); o->filter = argparser_keyword_present(pp, "-filter"); if ((argparser_keyword_present(pp, "-silhouette"))) { o->silhouette = TRUE; if ((argparser_keyword_present(pp, "-color"))) { for (j = 0; j < 3; j++) { o->color[j] = pp.getNextReal(0.0,1.0); } } else { o->color = (frgb_t){1.0,1.0,0.85}; } if ((argparser_keyword_present(pp, "-opacity"))) { o->opacity = pp.getNextReal(0.0,1.0); } else { o->opacity = 0.85; } } argparser_get_keyword(pp, "-projection"); o->projectionName = argparser_get_next(pp); if ((! 0 == strcmp(o->projectionName, "Parallel") OR Text.Equal(o->projectionName, "Perspective")) )){ argparser_error(pp, "Bad projection \"" & argparser_get_next(pp) & "\"\n") } if ((argparser_keyword_present(pp, "-normalize"))) { /* Desired radius of model in R^4 */ o->normalize = pp.getNextLongReal(1.0d-10,1.0d+10); } else { o->normalize = 0.0 /* No normalization */ } if ((argparser_keyword_present(pp, "-autoProject"))) { o->autoProject = TRUE } else { if ((argparser_keyword_present(pp, "-From4"))) { for (j = 0; j < 4; j++) { o->From4[j] = pp.getNextLongReal(-100.0, 100.0); } } else { o->From4 = (r4_t){0.0,0.0,0.0,-3.0}; } if ((argparser_keyword_present(pp, "-To4"))) { for (j = 0; j < 4; j++) { o->To4[j] = pp.getNextLongReal(-100.0, 100.0); } } else { o->To4 = (r4_t){0.0,0.0,0.0,0.0}; } if ((argparser_keyword_present(pp, "-Up4"))) { for (j = 0; j < 4; j++) { o->Up4[j] = pp.getNextLongReal(-100.0, 100.0); } } else { o->Up4 = (r4_t){0.0,1.0,0.0,0.0}; } if ((argparser_keyword_present(pp, "-Over4"))) { for (j = 0; j < 4; j++) { o->Over4[j] = pp.getNextLongReal(-100.0, 100.0); } } else { o->Over4 = (r4_t){0.0,0.0,1.0,0.0}; } } if ((argparser_keyword_present(pp, "-Vangle4"))) { o->Vangle4 = pp.getNextLongReal(1.0, 179.0); } else { o->Vangle4 = 25.0; } if ((argparser_keyword_present(pp, "-cell"))) { o->cell = argparser_get_next_int(pp, 1, 24); } argparser_finish(pp); ----------------------------------- #define _HELP \ fprintf(stderr, "Usage: Halo \\\n"); fprintf(stderr," -inFileTp -inFileSt \\\n"); fprintf(stderr," [ -outFile ] [ -all ] \\\n"); fprintf(stderr, " -projection [ Perspective | Parallel ]\\\n"); fprintf(stderr, " [ [ -autoProject ] | \\\n"); fprintf(stderr, " [ -From4 ] \\\n"); fprintf(stderr, " [ -To4 ] \\\n"); fprintf(stderr, " [ -Up4 ] \\\n"); fprintf(stderr, " [ -Over4 ]\\\n"); fprintf(stderr, " ] [ -Vangle4 ] \\\n"); fprintf(stderr," [ -silhouette [ -color | -opacity | -filter ] ]\\\n"); fprintf(stderr," [ -cell ]\n"); END¦ } } return o; } /* END GetOptions */ /* end Halo */ /* Copyright © 2000 Universidade Estadual de Campinas (UNICAMP) */