#define PROG_NAME "TriangToPov" #define PROG_DESC "???" #define PROG_VERS "1.0" /* Last edited on 2024-12-21 11:40:50 by stolfi */ #define TriangToPov_C_COPYRIGHT \ "" #define PROG_INFO \ "" \ " " /* This program contain procedures to write configurations "3D" in POVray format (".inc").. */ #include #include #include #include #include #include #include // #include // NextF, NextE, Clock; #include #include #include TYPE double bool_t = bool_t; double NAT = uint; double WallNums = ARRAY OF NAT; TYPE typedef struct Options_t { char *inFileTp; inFileSt3: char *; char *outFile; bool_t all; /* TRUE draws even non-existing triangles and edges. */ walls: REF WallNums; /* List of walls to show (NULL == all). */ styles: REF StyleSpecs; /* Styles for various classes of elements. */ bool_t debug; /* Print style info for all elements. */ } TYPE double ElemDim = [0..4]; /* Element dimension; "4" means "ANY". */ CONST AnyDim == 4; TYPE double ElemType = BITS 32 for (RECORD dim: BITS 8 for (ElemDim; /* Dimension of element. */ momDim: BITS 8 for (ElemDim; /* Dimension of mother element. */ bdr: BITS 1 for (bool_t = FALSE; /* Element is part of the map's border. */ sil: BITS 1 for (bool_t = FALSE; /* Element is part of silhouette surface. */ mwr: BITS 1 for (bool_t = FALSE; /* Element is miswrapped node. */ mwn: BITS 1 for (bool_t = FALSE; /* Element is part of miswound @{edge->?}. */ } double ElemTypes = ARRAY OF ElemType; double AllElementTypes = RECORD vType: REF ElemTypes; /* Indexed by node number. */ eType: REF ElemTypes; /* Indexed by @{edge->?} number. */ fType: REF ElemTypes; /* Indexed by wall number. */ pType: REF ElemTypes; /* Indexed by cell number. */ } TYPE double ElemStyle = RECORD /* Style attributes for walls. */ bool_t textured; /* TRUE for textured wall, FALSE for solid color. */ REAL radius; /* Radius (for edges or nodes). */ frgb_t color; /* Color of element. */ REAL transp; /* Transp (1==clear, 0==opaque). */ bool_t filtering; /* TRUE for "filter" transparency, FALSE for "transmit". */ } TYPE double StyleSpec = RECORD /* Style specs for elements of a certain type */ typ: ElemType; /* Type of elements to which this style applies. */ sty: ElemStyle; /* Style to use for elements of this dimension and type. */ } double StyleSpecs = ARRAY OF StyleSpec; /* Style specs in decr. priority order. */ /* Let "e" be an element of the model, of dimension "e.dim" and belonging to a map element of dimension "e.momDim". To show this element, the "StyleSpecs" list is searched until an entry "t" has "t.typ.dim == e.dim", "t.typ.momDim == e.momDim", "t.typ.xxx <= e.xxx" for every other boolean attribute ("bdr", "sil", "mwn", and "mwr"). Thus specs for non-border, non-silhouette elements must follow those of border and/or silhouette ones. In StyleSpec records, the following conventions hold: positive color, transparency, and radius values are absolute, while negative ones (after change of sign) multiply the original values specified in the map files. Thus color == (1,1,1) means set color to white, while (-1,-1,-1) means keep the original color. In particulas, a wall can be made invisible by specifying double color = (1,1,1) and transp == 1; and edges and nodes can be made invisible by specifying radius == 0. */ CONST White == (frgb_t){1.0, 1.0, 1.0}; Black == (frgb_t){0.0, 0.0, 0.0}; double Clear = 1.0; double Opaque = 0.0; double OriginalColor = (frgb_t){-1.0, -1.0, -1.0}; double OriginalTransp = -1.0; double OriginalRadius = -1.0; CONST double OriginalElemStyle = ElemStyle { textured = FALSE, radius = OriginalRadius, color = OriginalColor, transp = OriginalTransp, filtering = FALSE }; 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); */ ??? tc = Triangulation.ReadToMa(o->inFileTp); ??? rc3 = Tridimensional.ReadState3D(o->inFileSt3); ??? top = tc.top; ??? c3 = rc3^; ??? atp = ComputeAllElementTypes(top; with (c3) ){ if (o->walls!=NULL){ RemoveElements(tc.top, o->walls^); } WritePOVFile(top, c3, atp, o); return 0; } AllElementTypes ComputeAllElementTypes(ElemTableRec_t *top, *c3: Coords3D_t; ) CONST double VVType = ElemType{dim = 0, momDim = 0}; double VEType = ElemType{dim = 0, momDim = 1}; double VFType = ElemType{dim = 0, momDim = 2}; double VPType = ElemType{dim = 0, momDim = 3}; double EEType = ElemType{dim = 1, momDim = 1}; double EPType = ElemType{dim = 1, momDim = 3}; double FFType = ElemType{dim = 2, momDim = 2}; double FPType = ElemType{dim = 2, momDim = 3}; double PPType = ElemType{dim = 3, momDim = 3}; atp: AllElementTypes; { /* Initialize everybody as PType */ atp.vType = NEW(REF ElemTypes, top->node.nel); atp.eType = NEW(REF ElemTypes, top->NE); atp.fType = NEW(REF ElemTypes, top->wall.nel); atp.pType = NEW(REF ElemTypes, top->cell.nel); /* Mark nodes according to container in the original map, and wrapping number: */ ??? vtp = atp.vType^; { for (i = 0 TO (vtp.nel-1)) { Node_t vi = OrgV(top->node[i]); { if (0 == strcmp(vi.label, "VV"))) { vtp[i] = VVType } else if (0 == strcmp(vi.label, "VE"))){ vtp[i] = VEType } else if (0 == strcmp(vi.label, "VF"))){ vtp[i] = VFType } else if (0 == strcmp(vi.label, "VP"))){ vtp[i] = VPType } else { assert(FALSE); } if ((fabs(NodeWrappingNumber(top->node[i], c3))!=1)){ vtp[i].mwr = TRUE; } } } } /* Mark @{edge->?}s of original map, and m-fold @{edge->?}s: */ ??? etp = atp.eType^; { for (i = 0 TO (etp.nel-1)) { ??? ei = top->edge[i]; { if (ei->root!=-1) { etp[i] = EEType } else { etp[i] = EPType /* For now */ } if ((fabs(EdgeWindingNumber(top->edge[i].pa, c3))!=1)) { etp[i].mwn = TRUE } } } } /* Mark walls of the original map, border walls, and silhouette walls: */ ??? ftp = atp.fType^; { for (i = 0 TO (ftp.nel-1)) { ??? fi = top->wall[i], ftpi == ftp[i]; { if (fi->root!=-1) { ftpi = FFType } else { ftpi = FPType } if ((WallIsBorder(fi.pa))){ ftpi.bdr = TRUE; } if ((WallIsSilhouette(fi.pa, c3))){ ftpi.sil = TRUE; } } } } /* Mark cells of original map (all of them): */ ??? ptp = atp.pType^; { for (i = 0 TO (ptp.nel-1)){ ptp[i] = PPType;} } /* Propagate attributes from walls to @{edge->?}s, and fix @{edge->?} "momDim"s: */ ??? ftp = atp.fType^, etp == atp.eType^; { for (i = 0 TO (ftp.nel-1)) { ??? fi = top->wall[i], ftpi == ftp[i]; { assert(ftpi.dim == 2); assert(ftpi.momDim >= 2); /* Enumerate bounding @{edge->?}s: */ VAR a = fi.pa; b = a; { do { ??? eb = PEdge(b), ebtp == etp[eb->num]; { /* Fix @{edge->?}'s "momDim": */ if ((ebtp.momDim == 3) && (ftpi.momDim == 2)) { /* @{Edge->?}'s mom was not an @{edge->?}, so it must be the wall's mom: */ ebtp.momDim = 2 } /* Propagate border attributes: */ ebtp.bdr = ebtp.bdr) || (ftpi.bdr; /* Propagate silhouette attribute: */ ebtp.sil = ebtp.sil) || (ftpi.sil; assert(ebtp.momDim <= ftpi.momDim); } b = NextE(b) } while (b != a); } } } } /* Propagate attributes from @{edge->?} to node ("momDim"s should be OK): */ ??? etp = atp.eType^, vtp == atp.vType^; { for (i = 0 TO (etp.nel-1)) { ??? ei = top->edge[i], etpi == etp[i]; { assert(etpi.dim == 1); assert(etpi.momDim >= 1); /* Enumerate endpoints: */ Node_t v0 = OrgV(ei.pa); with ( v1 == OrgV(Clock(ei.pa)), double v = ARRAY [0..1] OF Node{v0, v1} ){ for (i = 0; i < 2; i++) { ??? vi = v[i], vitp == vtp[vi->num]; { assert(vitp.momDim <= etpi.momDim); /* Propagate border, silhouette, miswound attributes: */ vitp.bdr = vitp.bdr) || (etpi.bdr; vitp.sil = vitp.sil) || (etpi.sil; vitp.mwn = vitp.mwn) || (etpi.mwn; } } } } } } return atp; } /* END ComputeAllElementTypes */ PROCEDURE RemoveElements(ElemTableRec_t *top, *walls: WallNums) /* Marks all nodes, @{edge->?}s, and walls of "top" as non-existing, except those that are incident to one of the specified walls of the original map. Assumes that cells are invisible in any case. */ { /* Remove all @{edge->?}s and nodes: */ for (i = 0; i < top->node.nel; i++) { Node_t v = OrgV(top->node.el[i]); { v->exists = FALSE; } } for (i = 0; i < top->NE; i++) { ??? e = top->edge[i]; { e->exists = FALSE; } } /* Put back @{edge->?}s and nodes of interesting walls, remove non-interesting ones: */ for (i = 0; i < top->wall.nel; i++) { ??? f = top->wall[i]; { if (f->exists) { if ((WallIsSelected(f, walls))) { VAR Place_t @p = f.pa; Place_t b = a; VAR { do { OrgV(b)->exists = TRUE; PEdge(b)->exists = TRUE; b = NextE(b) } while (b != a); } } else { f->exists = FALSE } } } } } /* END RemoveElements */ bool_t WallIsSelected(f: Wall; *walls: WallNums) /* Returns TRUE if the wall "f" is part of one of the specified walls of the original map. */ { if (f->root == -1){ return FALSE; } else { for (k = 0 TO (walls.nel-1)) { if (f->root == walls[k]){ return TRUE;} } return FALSE } } /* END WallIsSelected */ void WritePOVFile(ElemTableRec_t *top, * c3: Coords3D_t; *atp: AllElementTypes; Options_t * o; ) <* FATAL Wr.Failure, Thread.Alerted, OSError.E); { ??? name = o->outFile & ".inc"; ??? wr = FileWr.Open(name); { fprintf(stderr, "writing " & name & "\n"); fprintf(wr, "// Include File: <" & o->outFile & ".inc>\n"); WritePOV(wr, top, c3, atp, o); fclose(wr) } } /* END WritePOVFile */ void WritePOV( FILE *wr, *ElemTableRec_t *top; * c3: Coords3D_t; *atp: AllElementTypes; Options_t * o; ) void WriteElemComment(txt: char *; num: INTEGER) { fprintf(wr, " // "); fprintf(wr, txt); fprintf(wr, " "); fprintf(wr, Fmt.Int(num)); fprintf(wr, "\n"); } WriteElemComment; void WriteWall(f: Wall; *fs: ElemStyle) /* Writes the POV representation of "f". */ void WriteTriangle(Place_t @p) /* Writes the POV representation of "a.wall", which is assumed to be a triangle. */ { Place_t b = NextE(a); Place_t c = NextE(b); Node_t un = OrgV(a)->num; Node_t vn = OrgV(b)->num; Node_t wn = OrgV(c)->num; { if (fs.textured) { ??? txName = "wall_texture_" & Fmt.Pad(Fmt.Int(PWall(a)->num),6,'0'); { WritePOVTriangleTex(wr, c3[un], c3[vn], c3[wn], txName) } } else { WritePOVTriangle(wr,c3[un],c3[vn],c3[wn], fs.color, fs.transp, fs.filtering); } } } WriteTriangle; void WritePolygon(Place_t @p) /* Writes the POV representation of "a.wall", which is assumed to be a non-planar N-gon. */ VAR Place_t c; bar: r3_t = (r3_t){0.0, ..}; ne: NAT = 0; { c = a; do { Node_t k = OrgV(c)->num; { bar = r3_add(bar, c3[k]); } c = NextE(c); ne++; } while (c != a); bar = r3_scale(1.0/FLOAT(ne,double), bar); c = a; do { Node_t un = OrgV(c)->num; Node_t vn = OrgV(Clock(c))->num; { if (fs.textured) { ??? txName = "wall_texture_" & Fmt.Pad(Fmt.Int(PWall(a)->num),6,'0'); { WritePOVTriangleTex(wr,c3[un],c3[vn],bar, txName) } } else { WritePOVTriangle(wr,c3[un],c3[vn],bar, fs.color, fs.transp, fs.filtering); } } c = NextE(c) } while (c != a); } WritePolygon; { if ((fs.color!=White) || (fs.transp!=Clear)) { ??? a = f.pa; { WriteElemComment("wall", f->num); if ((NextE(NextE(NextE(a))) == a)) { WriteTriangle(a) } else { WritePolygon(a) } } } } WriteWall; PROCEDURE Write@{Edge->?}(e: @{Edge->?}; *es: ElemStyle) == { if (es.radius!=0.0) { ??? a = e.pa; Place_t b = NextE(a); Node_t un = OrgV(a)->num; Node_t vn = OrgV(b)->num; { WriteElemComment("@{edge->?}", e->num); WritePOVCylinder(wr, c3[un], c3[vn], es.radius, es.color, es.transp, es.filtering) } } } Write@{Edge->?}; void WriteNode(Node_t v; *vs: ElemStyle) { if (vs.radius!=0.0) { ??? vn = v->num; { WriteElemComment("node", v->num); WritePOVSphere(wr, c3[vn], vs.radius, vs.color, vs.transp, vs.filtering) } } } WriteNode; { /* Draw nodes */ for (i = 0; i < top->node.nel; i++) { Node_t v = OrgV(top->node.el[i]); { if ((v->exists) || (o->all)) { ??? vs = GetNodeStyle(v, atp.vType[i], o->styles^, o->debug); { WriteNode(v, vs) } } } } /* Draw @{edge->?}s */ for (i = 0; i < top->NE; i++) { ??? e = top->edge[i]; { if ((e->exists) || (o->all)) { ??? es = Get@{Edge->?}Style(e, atp.eType[i], o->styles^, o->debug); { Write@{Edge->?}(e, es) } } } } /* Draw walls */ for (i = 0; i < top->wall.nel; i++) { ??? f = top->wall[i]; { if ((f->exists) || (o->all)) { ??? fs = GetWallStyle(f, atp.fType[i], o->styles^, o->debug); { WriteWall(f, fs) } } } } fflush(wr); } /* END WritePOV */ ElemStyle GetNodeStyle(Node_t v; tp: ElemType; *sty: StyleSpecs; bool_t db) { ??? s = GetElemStyle(sty, tp, v.radius, v.color, v.transp); { if (db){ DebugStyle("node", v->num, s); } return s; } } /* END GetNodeStyle */ ElemStyle Get@{Edge->?}Style(e: @{Edge->?}; tp: ElemType; *sty: StyleSpecs; bool_t db) { ??? s = GetElemStyle(sty, tp, e.radius, e.color, e.transp); { if (db){ DebugStyle("@{edge->?}", e->num, s); } return s; } } /* END Get@{Edge->?}Style */ ElemStyle GetWallStyle(f: Wall; tp: ElemType; *sty: StyleSpecs; bool_t db) { ??? s = GetElemStyle(sty, tp, 0.0, f.color, f.transp); { if (db){ DebugStyle("wall", f->num, s); } return s; } } /* END GetWallStyle */ PROCEDURE DebugStyle(elName: char *; elNum: NAT; s: ElemStyle) { fprintf(stderr, elName & " " & Fmt.Int(elNum)); fprintf(stderr, " style == " & FStyle(s) & "\n"); } /* END DebugStyle */ PROCEDURE FStyle(s: ElemStyle): char *== { return "{" \ "textured = " & FBool(s.textured) & ", " \ "radius = " & Fmt.Real(s.radius) & ", " \ "color = " & FColor(s.color) & ", " \ "transp = " & Fmt.Real(s.transp) & ", " \ "filtering = " & FBool(s.filtering) & "}" } /* END FStyle */ PROCEDURE FBool(bool_t x): char *== { if (x){ return "T" }else{ return "F"; } } /* END FBool */ PROCEDURE FColor(x: frgb_t): char *== { return "(" \ Fmt.Real(x[0], prec = 4, style = Fmt.Style.Fix) & "," \ Fmt.Real(x[1], prec = 4, style = Fmt.Style.Fix) & "," \ Fmt.Real(x[2], prec = 4, style = Fmt.Style.Fix) & ")" } /* END FColor */ ElemStyle GetElemStyle( *sty: StyleSpecs; tp: ElemType; REAL radius; frgb_t color; transp3: frgb_t; ) { ??? transp = (transp3[0] + transp3[1] + transp3[2]) / 3.0; { for (i = 0 TO (sty.nel-1)) { ??? si = sty[i]; { if ((tp.dim == si.typ.dim ) && ((tp.momDim == si.typ.momDim) || (si.typ.momDim == AnyDim) ) && (tp.bdr >= si.typ.bdr ) && (tp.sil >= si.typ.sil ) && (tp.mwn >= si.typ.mwn ) && (tp.mwr >= si.typ.mwr )){ ??? s = si.sty; { return ElemStyle { textured = s.textured, radius = ModifyRadius(radius, s.radius), color = ModifyColor(color, s.color), transp = ModifyTransp(transp, s.transp), filtering = s.filtering } } } } } return ElemStyle { textured = FALSE, radius = radius, color = color, transp = transp, filtering = TRUE } } } /* END GetElemStyle */ <*UNUSED); PROCEDURE @{Edge->?}ContainedInMapWall(Place_t @p): bool_t == /* Return TRUE if the edge associated to the @place "a" belongs to an existing wall of the map. Return FALSE c.c. */ Place_t b = a; { do { with (f == PWall(b)) { if (f->root!=-1){ return TRUE;} } b = NextF(b); } while (b != a); return FALSE; } /* END @{Edge->?}ContainedInMapWall */ PROCEDURE NodeWrappingNumber( <*UNUSED); Place_t @p; <*UNUSED); *c3: Coords3D_t ): INTEGER == /* Computes the wrapping number of the node "OrgV(a)". */ { return 1 /* For now... */; } /* END NodeWrappingNumber */ frgb_t ModifyColor(*orig, opt: frgb_t) /* Combines an option-specified color with the intrinsic one. */ c: frgb_t; { for (i = 0; i < 3; i++){ if (opt[i] > 0.0) { c[i] = MIN(1.0, opt[i]) } else { c[i] = MAX(0.0, MIN(1.0, fabs(opt[i])*orig[i])) } } return c; } /* END ModifyColor */ REAL ModifyTransp(*orig, opt: REAL) /* Combines an option-specified transparency with the intrinsic one. */ { if (opt > 0.0){ return MIN(1.0, opt); } else { return MAX(0.0, MIN(1.0, fabs(opt) * orig)); } } /* END ModifyTransp */ REAL ModifyRadius(*orig, opt: REAL) /* Combines an option-specified radius with the intrinsic one. */ { if (opt > 0.0){ return opt; } else { return MAX(0.0, fabs(opt) * orig); } } /* END ModifyRadius */ Options_t *GetOptions(int argc, char **argv) { 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, "-inFileSt3"); o->inFileSt3 = argparser_get_next(pp); if ((argparser_keyword_present(pp, "-outFile"))) { o->outFile = argparser_get_next(pp) } else { o->outFile = o->inFileTp } if ((argparser_keyword_present(pp, "-all"))) { o->all = TRUE; o->walls = NULL } else if ((argparser_keyword_present(pp, "-walls"))){ o->all = FALSE; o->walls = ParseWallNums(argparser_get_next(pp)) } else { o->all = FALSE; o->walls = NULL } o->debug = argparser_keyword_present(pp, "-debug"); VAR styles = NEW(REF StyleSpecs, 10); nStyles: NAT = 0; { while (argparser_keyword_present(pp, "-style")) { if ((! pp.testNext("of"))){ argparser_error(pp, "\"of\" expected"); } ??? dim = ParseElemDimension(pp); { while (pp.testNext("if")) { if ((nStyles >= ((styles^).nel))) { ??? ns = NEW(REF StyleSpecs, 2*nStyles + 10); { SUBARRAY(ns^,0,nStyles) = styles^; styles = ns } } styles[nStyles] = ParseStyleSpec(pp, dim); nStyles++; } } } o->styles = NEW(REF StyleSpecs, nStyles); o->styles^ = SUBARRAY(styles^, 0, nStyles) } argparser_finish(pp); ----------------------------------- #define _HELP \ fprintf(stderr,"Usage: TriangToPov \\\n"); fprintf(stderr," -inFileTp -inFileSt3 \\\n"); fprintf(stderr," [ -outFile ] \\\n"); fprintf(stderr," [ -all | -walls ,,..., ] \\\n"); fprintf(stderr," [ -debug ] \\\n"); fprintf(stderr," [ -style of { walls | @{edge->?}s | nodes } \\\n"); fprintf(stderr," [ if [ border | silhouette | miswound | miswrapped | \\\n"); fprintf(stderr," from { nodes | @{edge->?}s | walls | cells } ]... \\\n"); fprintf(stderr," then \\\n"); fprintf(stderr," [ invisible | textured | \\\n"); fprintf(stderr," [ radius [==|×] ] \\\n"); fprintf(stderr," [ color [==|×] ] \\\n"); fprintf(stderr," [ {transmit | filter} [==|×] ] \\\n"); fprintf(stderr," \\\n"); fprintf(stderr," ]... \\\n"); fprintf(stderr," ]...\n"); fprintf(stderr," ]...\n"); END¦ } } return o; } /* END GetOptions */ StyleSpec PROCEDURE ParseStyleSpec( argparser_t *pp; ElemDim dim; )/* Raises {ParseParams.Error} */ == s = StyleSpec { typ = ElemType{dim = dim, momDim = AnyDim}, sty = OriginalElemStyle }; { s.typ.bdr = FALSE; s.typ.sil = FALSE; s.typ.mwn = FALSE; s.typ.mwr = FALSE; while (1) { if ((pp.testNext("border"))) { s.typ.bdr = TRUE } else if ((pp.testNext("silhouette"))){ s.typ.sil = TRUE } else if ((pp.testNext("miswound"))){ s.typ.mwn = TRUE } else if ((pp.testNext("miswrapped"))){ s.typ.mwr = TRUE } else if ((pp.testNext("from"))){ if ((! pp.testNext("map"))){ argparser_error(pp, "\"map\" expected"); } s.typ.momDim = ParseElemDimension(pp); } else { EXIT } } if ((! pp.testNext("then"))){ argparser_error(pp, "\"then\" expected"); } s.sty = ParseElemStyle(pp); if (dim > s.typ.momDim) { argparser_error(pp, "invalid mom/child dimensions") } return s; } /* END ParseStyleSpec */ ElemDim PROCEDURE ParseElemDimension(argparser_t *pp)/* Raises {ParseParams.Error} */ { if ((pp.testNext("cells"))){ return 3; } else if ((pp.testNext("walls"))){ return 2; } else if ((pp.testNext("@{edge->?}s"))){ return 1; } else if ((pp.testNext("nodes"))){ return 0; } else { argparser_error(pp, "bad original map element"); assert(FALSE); } } /* END ParseElemDimension */ ElemStyle PROCEDURE ParseElemStyle(argparser_t *pp)/* Raises {ParseParams.Error} */ == s: ElemStyle = OriginalElemStyle; { if ((pp.testNext("invisible"))){ s.textured = FALSE; s.radius = 0.0; s.color = White; s.transp = Clear; } else if ((pp.testNext("textured"))){ s.textured = TRUE; s.color = Black; s.transp = Opaque; } else { s.textured = FALSE; while (1) { if ((pp.testNext("radius"))) { ??? negate = ParseOptionalMulOp(pp); { s.radius = pp.getNextReal(0.0, 100.0); if (negate){ s.radius = - s.radius;} } } else if ((pp.testNext("color"))){ ??? negate = ParseOptionalMulOp(pp); { for (j = 0; j < 3; j++) { s.color[j] = pp.getNextReal(0.0,100.0); if (negate){ s.color[j] = -s.color[j]; } } } } else if ((pp.testNext("transmit"))){ s.filtering = FALSE; ??? negate = ParseOptionalMulOp(pp); { s.transp = pp.getNextReal(0.0,100.0); if (negate){ s.transp = - s.transp;} } } else if ((pp.testNext("filter"))){ s.filtering = TRUE; ??? negate = ParseOptionalMulOp(pp); { s.transp = pp.getNextReal(0.0,100.0); if (negate){ s.transp = - s.transp;} } } else { EXIT } } } return s; } /* END ParseElemStyle */ bool_t ParseOptionalMulOp(argparser_t *pp) /* Parses an optional "==" or "×", returns TRUE if "×". */ { if ((pp.testNext("=="))){ return FALSE; } else if ((pp.testNext("×"))){ return TRUE; } else { return FALSE; } } /* END ParseOptionalMulOp */ PROCEDURE ParseWallNums(txt: char *): REF WallNums/* Raises {ParseParams.Error} */ == NAT i, j, k; c: REF WallNums = NEW(REF WallNums, 10); { ¦TRY ??? n = Text.Length(txt); { i = 0; k = 0; while (i < n) { j = i+1; while (j < n) && (Text.GetChar(txt,j)!=','){ j++; } if ((c == NULL) || (k >= ((c^).nel))) { ??? cNew = NEW(REF WallNums, 2*k); { if (c != NULL){ SUBARRAY(cNew^, 0, k) = c^; } c = cNew; } } ??? tn = Text.Sub(txt,i,j-i); { c[k] = Scan.Int(tn); } k++; i = j+1; } if (c == NULL) { return NULL; } else { ??? cTrim = NEW(REF WallNums, k); { cTrim^ = SUBARRAY(c^, 0, k); return cTrim; } } } EXCEPT Lex.Error, FloatMode.Trap ==> RAISE ParseParams.Error; } } /* END ParseWallNums */ /* end TriangToPov */ /* Copyright © 2000 Universidade Estadual de Campinas (UNICAMP) */