| 1 | A general scheme has been defined for writing translators from CAD | 
| 2 | files to Radiance.  This scheme should be used by anyone who writes a | 
| 3 | new translator, since it is both useful and general. | 
| 4 |  | 
| 5 | One of the biggest problems encountered when importing CAD descriptions | 
| 6 | to a lighting simulation (or any good rendering program) is assigning | 
| 7 | materials to the surface geometry.  Even if the creator of the model | 
| 8 | has been careful to make 3d surfaces instead of points and lines, most | 
| 9 | people don't even think about what a surface is made of until they're | 
| 10 | all done.  At that point, of course, it's too late.  Even if the user | 
| 11 | does give a little thought to materials, most CAD systems only permit | 
| 12 | the assignment of a color index to each surface, which is a start but | 
| 13 | far short of the information needed to make a good simulation. | 
| 14 |  | 
| 15 | There are only a few CAD systems that "do the right thing" and allow the | 
| 16 | user to assign material identifiers to objects and individual surfaces. | 
| 17 | Such a program, GDS for example, makes writing a translator almost | 
| 18 | trivial, since the material identifiers can refer back to a library of | 
| 19 | materials maintained by the user, or even imported from the CAD system. | 
| 20 |  | 
| 21 | Most CAD programs, like AutoCAD or Architrion, don't really use the | 
| 22 | notion of materials in their models at all.  Instead, they | 
| 23 | differentiate surfaces by layer, color, block name, and so forth, none | 
| 24 | of which clearly makes sense to use as a material identifier.  Even if | 
| 25 | the user creates a model with an intent to perform lighting | 
| 26 | simulations, he or she has no way to assign materials directly to the | 
| 27 | objects in the model. | 
| 28 |  | 
| 29 | The only general solution is to use every available piece of information | 
| 30 | from the CAD model to assign materials.  We can do this by using a set | 
| 31 | of mapping rules, created somehow by the user.  (We are working on | 
| 32 | a HyperCard interface for selecting materials that should be very nice | 
| 33 | if we ever finish it.)  The mapping rules are an ordered list of | 
| 34 | materials and the conditions a surface must satisfy in order to have | 
| 35 | that material. | 
| 36 |  | 
| 37 | For example, if we wanted all surfaces in the Block "thingy" with the | 
| 38 | Color 152 to use the material "wood", and all other surfaces to use the | 
| 39 | material "default", we would create the following mapping file: | 
| 40 |  | 
| 41 | default ; | 
| 42 | wood (Block "thingy") (Color 152) ; | 
| 43 |  | 
| 44 | All surfaces would satisfy the first set of conditions (which is empty), | 
| 45 | but only the surfaces in Block "thingy" with Color 152 would satisfy the | 
| 46 | second set of conditions. | 
| 47 |  | 
| 48 | Each rule can have up to one condition per qualifier, and different | 
| 49 | translators will use different qualifiers.  A qualifier is simply an | 
| 50 | attribute that can be used to distinguish surfaces, such as Color, | 
| 51 | Layer, Reference ID, etc.  A condition is either a single value for a | 
| 52 | specific attribute, or an integer range of values.  (Integer ranges are | 
| 53 | specified in brackets and separated by a colon, eg. [-15:27], and are | 
| 54 | always inclusive.)  A semicolon is used to indicate the end of a rule, | 
| 55 | which can extend over several lines if necessary. | 
| 56 |  | 
| 57 | The semantics of the rule are such that "and" is the implied conjunction | 
| 58 | between conditions.  Thus, it makes no sense to have more than one | 
| 59 | condition in a rule for a given qualifier.  If the user wants the same | 
| 60 | material to be used for surfaces that satisfy different conditions, | 
| 61 | they simply add more rules.  For example, if the user also wanted | 
| 62 | surfaces in Block "yohey" with Colors between 50 and 100 to use "wood", | 
| 63 | they would add the following rule to the end of the example above: | 
| 64 |  | 
| 65 | wood (Color [50:100]) (Block "yohey") ; | 
| 66 |  | 
| 67 | Note that the order of conditions in a rule is irrelevant.  However, | 
| 68 | the order of rules is very important, since the last rule satisfied | 
| 69 | determines which material a surface is assigned. | 
| 70 |  | 
| 71 | By convention, the identifier "void" is used to delete unwanted | 
| 72 | surfaces.  It is used in a rule as any other material, but it has the | 
| 73 | effect of excluding all matching surfaces from the translator output. | 
| 74 | For example, the following mapping would delete all surfaces in the | 
| 75 | Layer 2 except those with the color "beige", to which it would assign | 
| 76 | the material "beige_cloth", and all other surfaces would be "tacky": | 
| 77 |  | 
| 78 | tacky ; | 
| 79 | void (Layer 2) ; | 
| 80 | beige_cloth (Layer 2) (Color "beige") ; | 
| 81 |  | 
| 82 | Hopefully, the meaning of the mapping rules is now clear, so we can | 
| 83 | discuss ways to help the user create the mapping for a given model. | 
| 84 |  | 
| 85 | A translator should provide at least two basic options.  The first | 
| 86 | option, "-n", simply reads the CAD input file and creates a list of | 
| 87 | qualifiers and values that can be used to differentiate surfaces in the | 
| 88 | model.  The output of the program with "-n" should be something like: | 
| 89 |  | 
| 90 | filename "Example Input File" | 
| 91 | filetype "Architrion" | 
| 92 | qualifier Color begin | 
| 93 | 35 | 
| 94 | [100:110] | 
| 95 | 200 | 
| 96 | end | 
| 97 | qualifier RefId begin | 
| 98 | 1103 | 
| 99 | [5306:5307] | 
| 100 | "BIG Things" | 
| 101 | "little Things" | 
| 102 | end | 
| 103 | EOF | 
| 104 |  | 
| 105 | This information can be used either by the user or by a program such as | 
| 106 | HyperCard to create the rules for assigning materials to surfaces in | 
| 107 | the file.  (The "EOF" is literally there, since HyperCard has trouble | 
| 108 | detecting the end of file.) | 
| 109 |  | 
| 110 | The second option, "-m mapfile" is used to specify the mapping file to | 
| 111 | be used by the translator.  If no mapfile is provided by the user, the | 
| 112 | translator should have a standard mapping to assign material names | 
| 113 | based on some set of default paramters.  (For example, arch2rad uses | 
| 114 | color alone to assign materials "c0" through "c255".)  To accompany the | 
| 115 | default mapping, there should be a default materials file with | 
| 116 | corresponding definitions.  These files should be placed in the | 
| 117 | Radiance library directory under "lib" (ie. "/usr/local/lib/ray/lib"). | 
| 118 |  | 
| 119 | To just look at an Architrion building, a user might issue the following | 
| 120 | commands: | 
| 121 |  | 
| 122 | oconv '\!gensky 6 15 12' /usr/local/lib/ray/lib/arch.mat \ | 
| 123 | '\!arch2rad model.txt' > model.oct | 
| 124 | rvu -av 3 3 3 -vp -20 -20 5 -vd 1 1 0 model.oct | 
| 125 |  | 
| 126 | Note that by giving oconv commands instead of input files, no temporary | 
| 127 | files (other than the octree) are necessary.  In a more complete | 
| 128 | example, the user might first create a qualifier list, then run the | 
| 129 | HyperCard stack for assigning materials, then convert the model | 
| 130 | with his own materials file, thus: | 
| 131 |  | 
| 132 | arch2rad -n model.txt > model.qual | 
| 133 | HyperCard MatPick.stack         # creates model.map from model.qual | 
| 134 | arch2rad -m model.map model.txt > model.rad | 
| 135 | oconv source.rad materials.rad model.rad > model.oct | 
| 136 | rvu -vf model.vp model.oct | 
| 137 |  | 
| 138 | To write a new translator, include the "trans.h" file in ray/src/cv and | 
| 139 | link with trans.o and the standard Radiance library.  You will need to | 
| 140 | define your own list of valid qualifiers and use the following routines | 
| 141 | from trans.c: | 
| 142 |  | 
| 143 | fgetid(ID *idp; char *dls; FILE *fp) | 
| 144 | /* | 
| 145 | * Read an id (either a string or an integer) from fp | 
| 146 | * up to a character in dls.  The delimiter will be discarded. | 
| 147 | * Return EOF at end of file, 0 otherwise.  You should free | 
| 148 | * the id with the macro doneid(idp). | 
| 149 | */ | 
| 150 |  | 
| 151 | int | 
| 152 | findid(IDLIST *ilp; ID *idp; int insert) | 
| 153 | /* | 
| 154 | * Find (or insert) idp in the list ilp.  Uses binary search | 
| 155 | * to find (or if insert is true, insert) an id in a sorted id | 
| 156 | * list.  Returns index into ilp->id, or -1 if not found and no | 
| 157 | * insert. | 
| 158 | */ | 
| 159 |  | 
| 160 | int | 
| 161 | idcmp(ID *id1, *id2) | 
| 162 | /* | 
| 163 | * Compares two identifiers.  Numbers compare less than strings. | 
| 164 | */ | 
| 165 |  | 
| 166 | write_quals(QLIST *qlp; IDLIST idl[]; FILE *fp) | 
| 167 | /* | 
| 168 | * Write out qualifiers in array of id lists idl[] to fp. | 
| 169 | * The qualifier list qlp is used to determine how many and | 
| 170 | * what to call the qualifiers. | 
| 171 | */ | 
| 172 |  | 
| 173 | RULEHD * | 
| 174 | getmapping(char *file; QLIST *qlp) | 
| 175 | /* | 
| 176 | * Read mapping rules from "file" and create a list of rules | 
| 177 | * in reverse order.  Prints various syntax errors using eputs() | 
| 178 | * and calls quit() if there's a serious problem with the input. | 
| 179 | */ | 
| 180 |  | 
| 181 | matchid(ID *idp; IDMATCH *idm) | 
| 182 | /* | 
| 183 | * Checks to see if idp matches the id or range in idm. | 
| 184 | */ | 
| 185 |  | 
| 186 | Good luck!  I will be happy to answer questions ([email protected]). |