BRL-CAD
sh_treetherm.c
Go to the documentation of this file.
1 /* S H _ T R E E T H E R M . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2004-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @file liboptical/sh_treetherm.c
21  *
22  */
23 
24 #include "common.h"
25 
26 #include <stdlib.h>
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <math.h>
31 
32 #include "vmath.h"
33 #include "raytrace.h"
34 #include "optical.h"
35 #include "rtgeom.h"
36 
37 
38 #define tthrm_MAGIC 0x7468726d /* 'thrm' */
39 #define CK_tthrm_SP(_p) BU_CKMAG(_p, tthrm_MAGIC, "tthrm_specific")
40 
41 
42 /*
43  * The thermal data file starts with a long indicating the number of
44  * "cylinder" structures that follow. The cylinder structure consists
45  * of 18 bytes in 5 entries. First is a 2 byte short integer indicating the
46  * number of "segments" that follow. Max Lorenzo promises this value is
47  * always "1". A segment consists of n tuples. Max Lorenzo promises that
48  * "n" is always 8 (it's a compile-time option to treetherm). Each tuple
49  * consists of 4 (4-byte) float values: x, y, z, temperature.
50  *
51  * Because there is always 1 segment, the cylinder is a constant 130 bytes.
52  *
53  * So the file looks like:
54  *
55  * long #_of_cyls # Beware: may be 4 or 8 bytes!!!!
56  *
57  * short segs (always 1) # 2 bytes
58  * float x, y, z, temperature # 4 X 4 = 16 bytes
59  * float x, y, z, temperature # 4 X 4 = 16 bytes
60  * float x, y, z, temperature # 4 X 4 = 16 bytes
61  * float x, y, z, temperature # 4 X 4 = 16 bytes
62  * float x, y, z, temperature # 4 X 4 = 16 bytes
63  * float x, y, z, temperature # 4 X 4 = 16 bytes
64  * float x, y, z, temperature # 4 X 4 = 16 bytes
65  * float x, y, z, temperature # 4 X 4 = 16 bytes
66  *
67  * short segs (always 1)
68  * float x, y, z, temperature
69  * float x, y, z, temperature
70  * float x, y, z, temperature
71  * float x, y, z, temperature
72  * float x, y, z, temperature
73  * float x, y, z, temperature
74  * float x, y, z, temperature
75  * float x, y, z, temperature
76  *
77  * .
78  * .
79  * .
80  * .
81  */
82 /* return byte offset into file of "float x" in n'th cyl structure */
83 
84 
85 struct branch_seg {
87  struct branch_seg *bs_next; /* toward leaves/ends/tips */
88  struct branch_seg *bs_prev; /* toward root/source */
89 
90  point_t bs_start; /* location of segment start */
91  vect_t bs_dir; /* direction of segment */
92  double bs_length; /* length of segment */
93  double bs_sradius; /* start radius */
94  double bs_eradius; /* end radius */
95  double bs_dist; /* total distance from root */
96  float *bs_nodes[4]; /* point+temp for nodes */
97 };
98 
99 
100 #define NUM_NODES 8
101 #define THRM_SEG_MAGIC 246127
102 #define CK_THRM_SEG(_p) BU_CKMAG(_p, THRM_SEG_MAGIC, "thrm_seg")
103 struct thrm_seg {
104  uint32_t magic;
105  float pt[3]; /* center point of nodes */
106  float dir[3];
107  float node[NUM_NODES][3]; /* vectors from center to each node */
108  float vect[NUM_NODES][3]; /* vectors from center to each node */
109  float temperature[NUM_NODES]; /* temperature from treetherm file */
110 };
111 
112 
113 /*
114  * the shader specific structure contains all variables which are unique
115  * to any particular use of the shader.
116  */
118  uint32_t magic;
119  char tt_name[64];
124  struct bu_list *tt_br;
125  struct thrm_seg *tt_segs;
126  mat_t tthrm_m_to_sh; /* model to shader space matrix */
127 };
128 
129 
130 /* The default values for the variables in the shader specific structure */
131 #define SHDR_NULL ((struct tthrm_specific *)0)
132 #define SHDR_O(m) bu_offsetof(struct tthrm_specific, m)
133 
134 /* description of how to parse/print the arguments to the shader
135  * There is at least one line here for each variable in the shader specific
136  * structure above
137  */
139  {"%f", 1, "l", SHDR_O(tt_min_temp), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
140  {"%f", 1, "h", SHDR_O(tt_max_temp), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
141  {"%s", 64, "file", SHDR_O(tt_name), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
142  {"", 0, (char *)0, 0, BU_STRUCTPARSE_FUNC_NULL, NULL, NULL }
143 };
144 
145 
146 HIDDEN int tthrm_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *mfp, struct rt_i *rtip);
147 HIDDEN int tthrm_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp);
148 HIDDEN void tthrm_print(register struct region *rp, void *dp);
149 HIDDEN void tthrm_free(void *cp);
150 
151 /* The "mfuncs" structure defines the external interface to the shader.
152  * Note that more than one shader "name" can be associated with a given
153  * shader by defining more than one mfuncs struct in this array.
154  * See sh_phong.c for an example of building more than one shader "name"
155  * from a set of source functions. There you will find that "glass" "mirror"
156  * and "plastic" are all names for the same shader with different default
157  * values for the parameters.
158  */
159 struct mfuncs tthrm_mfuncs[] = {
160  {MF_MAGIC, "tthrm", 0, MFI_NORMAL|MFI_HIT|MFI_UV, 0, tthrm_setup, tthrm_render, tthrm_print, tthrm_free },
161  {0, (char *)0, 0, 0, 0, 0, 0, 0, 0 }
162 };
163 void
165 {
166  int i;
167  CK_THRM_SEG(ts);
168 
169  bu_log("Thermal cylinder\n");
170  bu_log("Center: (%g %g %g)\n", V3ARGS(ts->pt));
171  bu_log(" dir: (%g %g %g)\n", V3ARGS(ts->dir));
172  bu_log(" Nodes:\n");
173  for (i=0; i < NUM_NODES; i++) {
174 
175  bu_log("\t(%g %g %g) %17.14e (%g %g %g)\n",
176  V3ARGS(ts->node[i]),
177  ts->temperature[i],
178  V3ARGS(ts->vect[i])
179  );
180  }
181 }
182 
183 
184 void
185 tree_parse(struct bu_list *UNUSED(br), union tree *tr)
186 {
187  switch (tr->tr_b.tb_op) {
188  case OP_SOLID: break;
189  case OP_UNION: break;
190  case OP_INTERSECT: break;
191  case OP_SUBTRACT: break;
192  case OP_XOR: break;
193  case OP_REGION: break;
194  case OP_NOP: break;
195 /* Internal to library routines */
196  case OP_NOT: break;
197  case OP_GUARD: break;
198  case OP_XNOP: break;
199  case OP_NMG_TESS: break;
200 /* LIBWDB import/export interface to combinations */
201  case OP_DB_LEAF: break;
202  }
203 
204 }
205 
206 
207 void
208 build_tree(struct bu_list *br, struct region *rp)
209 {
210  tree_parse(br, rp->reg_treetop);
211 }
212 
213 
214 /*
215  * This routine is called (at prep time)
216  * once for each region which uses this shader.
217  * Any shader-specific initialization should be done here.
218  */
219 HIDDEN int
220 tthrm_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *UNUSED(mfp), struct rt_i *rtip)
221 
222 
223 /* pointer to reg_udata in *rp */
224 
225 /* New since 4.4 release */
226 {
227  register struct tthrm_specific *tthrm_sp;
228  struct bu_mapped_file *tt_file;
229  char *tt_data;
230  long cyl_tot = 0;
231  long tseg;
232  float *fp;
233  float fv[4];
234  double min_temp;
235  double max_temp;
236  point_t center;
237  point_t pt;
238  vect_t dir;
239  static const double inv_nodes = 1.0/8.0;
240  int node;
241  int i;
242  int long_size = 0;
243  size_t file_size_long;
244  size_t file_size_int;
245 
246  /* check the arguments */
247  RT_CHECK_RTI(rtip);
248  BU_CK_VLS(matparm);
249  RT_CK_REGION(rp);
250 
251  if (rdebug&RDEBUG_SHADE)
252  bu_log("tthrm_setup(Region:\"%s\", tthrm(%s))\n",
253  rp->reg_name, bu_vls_addr(matparm));
254 
255  /* Get memory for the shader parameters and shader-specific data */
256  BU_GET(tthrm_sp, struct tthrm_specific);
257  *dpp = tthrm_sp;
258  tthrm_sp->magic = tthrm_MAGIC;
259 
260  tthrm_sp->tt_name[0] = '\0';
261  tthrm_sp->tt_min_temp = tthrm_sp->tt_max_temp = 0.0;
262 
263  if (rdebug&RDEBUG_SHADE)
264  bu_log("Parsing: (%s)\n", bu_vls_addr(matparm));
265 
266  if (bu_struct_parse(matparm, tthrm_parse, (char *)tthrm_sp, NULL) < 0) {
267  bu_bomb(__FILE__);
268  }
269  if (tthrm_sp->tt_name[0] == '\0') {
270  bu_log("Must specify file for tthrm shader on %s (got \"%s\"\n",
271  rp->reg_name, bu_vls_addr(matparm));
272  bu_bomb(__FILE__);
273  }
274 
275  tt_file = bu_open_mapped_file(tthrm_sp->tt_name, (char *)NULL);
276  if (!tt_file) {
277  bu_log("Error mapping \"%s\"\n", tthrm_sp->tt_name);
278  bu_bomb("shader tthrm: can't get thermal data");
279  }
280  tt_data = (char *)tt_file->buf;
281 
282 
283  if (rdebug&RDEBUG_SHADE)
284  bu_log("tthrm_setup() data: %p total\n",
285  (void *)tt_data);
286 
287  /* Compute how big the file should be, so that we can guess
288  * at the size of the integer at the front of the file
289  */
290  file_size_int = sizeof(int) + *((int *)tt_data) *
291  (sizeof(short) + sizeof(float) * 4 * NUM_NODES);
292 
293  file_size_long = sizeof(long) + *((long *)tt_data) *
294  (sizeof(short) + sizeof(float) * 4 * NUM_NODES);
295 
296  switch (sizeof(long)) {
297  case 8:
298  if (tt_file->buflen == file_size_long) {
299  /* 64bit data on 64bit host */
300  long_size = sizeof(long);
301  tthrm_sp->tt_max_seg = cyl_tot = *((long *)tt_data);
302  } else if (tt_file->buflen == file_size_int) {
303  /* 32bit data on 32bit host */
304  long_size = sizeof(int);
305  tthrm_sp->tt_max_seg = cyl_tot = *((int *)tt_data);
306  }
307  break;
308  case 4:
309  if (tt_file->buflen == file_size_long) {
310  /* 32bit data on 32bit host */
311  long_size = sizeof(long);
312  tthrm_sp->tt_max_seg = cyl_tot = *((long *)tt_data);
313  } else if (tt_file->buflen == (file_size_long+4)) {
314  /* 64bit data on 32bit host */
315 
316  cyl_tot = *((int *)tt_data);
317  if (cyl_tot != 0) {
318  bu_log("%s:%d thermal data written on 64bit machine with more that 2^32 segs\n", __FILE__, __LINE__);
319  bu_bomb("");
320  }
321 
322  long_size = sizeof(long) + 4;
323  tthrm_sp->tt_max_seg = cyl_tot =
324  ((int *)tt_data)[1];
325  }
326  break;
327  default:
328  bu_log("a long int is %lu bytes on this machine\n", sizeof(long));
329  bu_bomb("I can only handle 4 or 8 byte longs\n");
330  break;
331  }
332 
333  if (rdebug&RDEBUG_SHADE)
334  bu_log("cyl_tot = %ld\n", cyl_tot);
335 
336  tthrm_sp->tt_segs = (struct thrm_seg *)
337  bu_calloc(cyl_tot, sizeof(struct thrm_seg), "thermal segs");
338 
339  min_temp = MAX_FASTF;
340  max_temp = -MAX_FASTF;
341 
342 #define CYL_DATA(_n) ((float *) (&tt_data[ \
343  long_size + \
344  (_n) * (sizeof(short) + sizeof(float) * 4 * NUM_NODES) + \
345  sizeof(short) \
346  ]))
347 
348  for (tseg = 0; tseg < cyl_tot; tseg++) {
349 
350  /* compute centerpoint, min/max temperature values */
351  fp = CYL_DATA(tseg);
352  VSETALL(center, 0.0);
353  for (node=0; node < NUM_NODES; node++, fp+=4) {
354  /* this is necessary to assure that all float
355  * values are aligned on 4-byte boundaries
356  */
357  memcpy(fv, fp, sizeof(float)*4);
358 
359  if (rdebug&RDEBUG_SHADE)
360  bu_log("tthrm_setup() node %d (%g %g %g) %g\n",
361  node, fv[0], fv[1], fv[2], fv[3]);
362 
363  /* make sure we don't have any "infinity" values */
364  for (i=0; i < 4; i++) {
365  if (fv[i] > MAX_FASTF || fv[i] < -MAX_FASTF) {
366  bu_log("%s:%d seg %ld node %d coord %d out of bounds: %g\n",
367  __FILE__, __LINE__, tseg, node, i, fv[i]);
368  bu_bomb("choke, gasp, *croak*\n");
369  }
370  }
371 
372  /* copy the values to the segment list, converting
373  * from Meters to Millimeters in the process
374  */
375  VSCALE(tthrm_sp->tt_segs[tseg].node[node], fv, 1000.0);
376  tthrm_sp->tt_segs[tseg].temperature[node] = fv[3];
377 
378  VADD2(center, center, fv);
379 
380  if (fv[3] > max_temp) max_temp = fv[3];
381  if (fv[3] < min_temp) min_temp = fv[3];
382  }
383 
384  VSCALE(center, center, 1000.0);
385  VSCALE(tthrm_sp->tt_segs[tseg].pt, center, inv_nodes);
386 
387  if (rdebug&RDEBUG_SHADE) {
388  bu_log("Center: (%g %g %g) (now in mm, not m)\n",
389  V3ARGS(tthrm_sp->tt_segs[tseg].pt));
390  }
391 
392  /* compute vectors from center pt for each node */
393  fp = CYL_DATA(tseg);
394  for (node=0; node < NUM_NODES; node++, fp+=4) {
395  /* this is necessary to assure that all float
396  * values are aligned on 4-byte boundaries
397  */
398  memcpy(fv, fp, sizeof(float)*4);
399 
400  VSCALE(pt, fv, 1000.0);
401  VSUB2(tthrm_sp->tt_segs[tseg].vect[node],
402  pt,
403  tthrm_sp->tt_segs[tseg].pt
404  );
405  }
406 
407  /* compute a direction vector for the thermal segment */
408  VCROSS(dir, tthrm_sp->tt_segs[tseg].vect[0],
409  tthrm_sp->tt_segs[tseg].vect[2]);
410  VUNITIZE(dir);
411  VMOVE(tthrm_sp->tt_segs[tseg].dir, dir);
412  tthrm_sp->tt_segs[tseg].magic = THRM_SEG_MAGIC;
413  }
414 
415  bu_close_mapped_file(tt_file);
416 
417  if (ZERO(tthrm_sp->tt_min_temp) && EQUAL(tthrm_sp->tt_max_temp, SMALL_FASTF)) {
418  tthrm_sp->tt_min_temp = min_temp;
419  tthrm_sp->tt_max_temp = max_temp;
420  bu_log("computed temp min/max on %s: %g/%g\n", rp->reg_name, min_temp, max_temp);
421  } else {
422  min_temp =tthrm_sp->tt_min_temp;
423  max_temp = tthrm_sp->tt_max_temp;
424  bu_log("taking user specified on %s: min/max %g/%g\n", rp->reg_name, min_temp, max_temp);
425  }
426 
427  if (!EQUAL(max_temp, min_temp)) {
428  tthrm_sp->tt_temp_scale = 1.0 / (max_temp - min_temp);
429  } else {
430  /* min and max are equal, maybe zero */
431  if (ZERO(max_temp))
432  tthrm_sp->tt_temp_scale = 0.0;
433  else
434  tthrm_sp->tt_temp_scale = 255.0/max_temp;
435  }
436  /* The shader needs to operate in a coordinate system which stays
437  * fixed on the region when the region is moved (as in animation)
438  * we need to get a matrix to perform the appropriate transform(s).
439  *
440  * Shading is done in "region coordinates":
441  */
443 
444  if (rdebug&RDEBUG_SHADE) {
445  bu_log("min_temp: %17.14e max_temp %17.14e temp_scale: %17.14e\n",
446  tthrm_sp->tt_min_temp,
447  tthrm_sp->tt_max_temp,
448  tthrm_sp->tt_temp_scale);
449 
450  bu_log("tthrm_setup(%s, %s)done\n",
451  rp->reg_name, bu_vls_addr(matparm));
452  tthrm_print(rp, *dpp);
453  }
454 
455  return 1;
456 }
457 
458 
459 HIDDEN void
460 tthrm_print(register struct region *UNUSED(rp), void *dp)
461 {
462  struct tthrm_specific *tthrm_sp = (struct tthrm_specific *)dp;
463 
464  bu_log("%s\n", tthrm_sp->tt_name);
465  bn_mat_print("m_to_sh", tthrm_sp->tthrm_m_to_sh);
466 }
467 
468 
469 HIDDEN void
470 tthrm_free(void *cp)
471 {
472  struct tthrm_specific *tthrm_sp = (struct tthrm_specific *)cp;
473 
474  bu_free(tthrm_sp->tt_segs, "thermal segs");
475  bu_free(tthrm_sp->tt_name, "bu_vls_strdup");
476 
477  tthrm_sp->tt_segs = (struct thrm_seg *)NULL;
478  tthrm_sp->tt_name[0] = '\0';
479  tthrm_sp->magic = 0;
480 
481  BU_PUT(cp, struct tthrm_specific);
482 }
483 
484 
485 /*
486  * God help us, we've got to extract the node number from the name
487  * of the solid that was hit.
488  */
489 static int
490 get_solid_number(const struct partition *pp)
491 {
492  char *solid_name;
493  char *solid_digits;
494 
495  solid_name = pp->pt_inseg->seg_stp->st_dp->d_namep;
496 
497  if (pp->pt_inseg->seg_stp->st_id != ID_PARTICLE) {
498  bu_log("%s:%d solid named %s isn't a particle\n",
499  __FILE__, __LINE__, solid_name);
500  bu_bomb("Choke! ack! gasp! wheeeeeeze.\n");
501  }
502 
503  solid_digits=strrchr(solid_name, (int)'_');
504  if (!solid_digits) {
505  bu_log("%s:%d solid name %s doesn't have '_'\n",
506  __FILE__, __LINE__, solid_name);
507  bu_bomb("Choke! ack! gasp! wheeeeeeze.\n");
508  }
509 
510  solid_digits++;
511 
512  if (! strlen(solid_digits)) {
513  bu_log("%s:%d solid name %s doesn't have digits after '_'\n",
514  __FILE__, __LINE__, solid_name);
515  bu_bomb("Choke! ack! gasp! wheeeeeeze.\n");
516  }
517 
518  return atoi(solid_digits);
519 }
520 
521 
522 /*
523  * This is called (from viewshade() in shade.c) once for each hit point
524  * to be shaded. The purpose here is to fill in values in the shadework
525  * structure.
526  */
527 int
528 tthrm_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
529 
530 
531 /* defined in material.h */
532 /* ptr to the shader-specific struct */
533 {
534  register struct tthrm_specific *tthrm_sp =
535  (struct tthrm_specific *)dp;
536  struct rt_part_internal *part_p;
537  char *solid_name;
538 
539  point_t pt;
540  vect_t pt_v;
541  vect_t v;
542  int solid_number;
543  struct thrm_seg *thrm_seg;
544  int best_idx;
545  double best_val;
546  double Vdot;
547  int node;
548 
549  solid_name = pp->pt_inseg->seg_stp->st_dp->d_namep;
550 
551  /* check the validity of the arguments we got */
552  RT_AP_CHECK(ap);
553  RT_CHECK_PT(pp);
554  CK_tthrm_SP(tthrm_sp);
555 
556  /* We are performing the shading in "region" space. We must
557  * transform the hit point from "model" space to "region" space.
558  * See the call to db_region_mat in tthrm_setup().
559  */
560  MAT4X3PNT(pt, tthrm_sp->tthrm_m_to_sh, swp->sw_hit.hit_point);
561 
562  if (rdebug&RDEBUG_SHADE)
563  bu_log("tthrm_render(%s, %g %g %g)\n", tthrm_sp->tt_name,
564  V3ARGS(pt));
565 
566 
567  solid_number = get_solid_number(pp);
568 
569  if (solid_number > tthrm_sp->tt_max_seg) {
570  bu_log("%s:%d solid name %s has solid number higher than %ld\n",
571  __FILE__, __LINE__, solid_name, tthrm_sp->tt_max_seg);
572  bu_bomb("Choke! ack! gasp! wheeeeeeze.\n");
573  }
574 
575  thrm_seg = &tthrm_sp->tt_segs[solid_number];
576  CK_THRM_SEG(thrm_seg);
577 
578 
579  /* Extract the solid parameters for the particle we hit,
580  * Compare them to the values for the node extracted. If they
581  * don't match, then we probably have a mis-match between the
582  * geometry and the treetherm output files.
583  */
584  if (pp->pt_inseg->seg_stp->st_id != ID_PARTICLE) {
585  bu_log("%d != ID_PART\n", pp->pt_inseg->seg_stp->st_id);
586  bu_bomb("");
587  }
588  part_p = (struct rt_part_internal *)pp->pt_inseg->seg_stp->st_specific;
589  RT_PART_CK_MAGIC(part_p);
590  VSUB2(v, part_p->part_V, thrm_seg->pt);
591  if (MAGSQ(v) > 100.0) {
592  double dist;
593  dist = MAGNITUDE(v);
594  /* Distance between particle origin and centroid of thermal
595  * segment nodes is > 10.0mm (1cm). This suggests that
596  * they aren't related.
597  */
598  bu_log(
599  "----------------------------- W A R N I N G -----------------------------\n\
600 %s:%d distance %g between origin of particle and thermal node centroid is\n\
601 too large. Probable mis-match between geometry and thermal data\n",
602  __FILE__, __LINE__, dist);
603  bu_bomb("");
604  }
605 
606 
607  if (rdebug&RDEBUG_SHADE) {
608  vect_t unit_H;
609  VMOVE(unit_H, part_p->part_H);
610  VUNITIZE(unit_H);
611 
612  bu_log("particle rooted at:\n\t(%g %g %g) radius %g\n\tdir: (%g %g %g) (%g %g %g)\n",
613  V3ARGS(part_p->part_V), part_p->part_vrad,
614  V3ARGS(unit_H),
615  V3ARGS(part_p->part_H));
616 
617  print_thrm_seg(thrm_seg);
618  }
619 
620  /* form vector from node center to hit point */
621  VSUB2(pt_v, pt, thrm_seg->pt);
622 
623  /* The output of treetherm is much too imprecise. Computed centroid
624  * from truncated floating point values is off. We'll try to
625  * compensate by doing a double-vector-cross product to get a vector
626  * for our point that is in the plane of the thermal node.
627  */
628  VUNITIZE(pt_v);
629  VCROSS(v, pt_v, thrm_seg->dir);
630 
631  VUNITIZE(v);
632  VCROSS(pt_v, thrm_seg->dir, v);
633 
634  VUNITIZE(pt_v);
635 
636  /* find closest node to hit point by comparing the vectors for the
637  * thermal nodes with the vector for the hit point in the plane
638  * of the nodes
639  */
640  best_idx = -1;
641  best_val = -2.0;
642 
643  for (node=0; node < NUM_NODES; node++) {
644  Vdot = VDOT(pt_v, thrm_seg->vect[node]);
645  if (Vdot > best_val) {
646  best_idx = node;
647  best_val = Vdot;
648  }
649  }
650 
651 
652  /* set color to temperature */
653  swp->sw_temperature = thrm_seg->temperature[best_idx];
654  best_val = (thrm_seg->temperature[best_idx] -
655  tthrm_sp->tt_min_temp) * tthrm_sp->tt_temp_scale;
656 
657  /* We do non-grayscale to indicate values
658  * outside the range specified
659  */
660  if (best_val > 1.0) {
661  /* hotter than maximum */
662  best_val -= 1.0;
663  if (best_val > 1.0) best_val = 1.0;
664  VSET(swp->sw_color, 1.0, best_val, 0.03921568);
665  } else if (best_val < 0.0) {
666  /* Colder than minimum */
667  best_val += 2.0;
668  if (best_val < 0.0) best_val = 0.0;
669 
670  VSET(swp->sw_color, 0.03921568, best_val, 1.0);
671  } else {
672  VSET(swp->sw_color, best_val, best_val, best_val);
673  }
674 
675  if (rdebug&RDEBUG_SHADE) {
676  bu_log("closest point is: (%g %g %g) temp: %17.14e\n",
677  V3ARGS(thrm_seg->node[best_idx]),
678  thrm_seg->temperature[best_idx]);
679 
680  bu_log("min_temp: %17.14e max_temp %17.14e temp_scale: %17.14e\n",
681  tthrm_sp->tt_min_temp,
682  tthrm_sp->tt_max_temp,
683  tthrm_sp->tt_temp_scale);
684 
685  bu_log("color: %g (%g)\n", best_val, best_val * 255.0);
686  }
687 
688 
689  if (rdebug&RDEBUG_SHADE) {
690  bu_log("tthrm_render()\n\t model:(%g %g %g)\n\t shader:(%g %g %g)\n",
691  V3ARGS(swp->sw_hit.hit_point),
692  V3ARGS(pt));
693  }
694  return 1;
695 }
696 
697 
698 /*
699  * Local Variables:
700  * mode: C
701  * tab-width: 8
702  * indent-tabs-mode: t
703  * c-file-style: "stroustrup"
704  * End:
705  * ex: shiftwidth=4 tabstop=8
706  */
char * d_namep
pointer to name string
Definition: raytrace.h:859
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
Definition: list.h:118
const struct directory * st_dp
Directory entry of solid.
Definition: raytrace.h:436
#define MF_MAGIC
Definition: magic.h:205
int tb_op
non-leaf
Definition: raytrace.h:1147
#define OP_NOP
Leaf with no effect.
Definition: raytrace.h:1132
struct soltab * seg_stp
pointer back to soltab
Definition: raytrace.h:372
fastf_t tt_max_temp
Definition: sh_treetherm.c:122
#define VSET(a, b, c, d)
Definition: color.c:53
#define OP_NMG_TESS
Leaf: tr_stp -> nmgregion.
Definition: raytrace.h:1137
#define VSETALL(a, s)
Definition: color.c:54
#define OP_XOR
Binary: L xor R, not both.
Definition: raytrace.h:1130
char tt_name[64]
Definition: sh_treetherm.c:119
#define ID_PARTICLE
Particle system solid.
Definition: raytrace.h:474
#define SMALL_FASTF
Definition: defines.h:342
#define NUM_NODES
Definition: sh_treetherm.c:100
float temperature[NUM_NODES]
Definition: sh_treetherm.c:109
Header file for the BRL-CAD common definitions.
#define OP_XNOP
Unary: L, mark region.
Definition: raytrace.h:1136
#define THRM_SEG_MAGIC
Definition: sh_treetherm.c:101
const char * reg_name
Identifying string.
Definition: raytrace.h:539
#define SHDR_O(m)
Definition: sh_treetherm.c:132
#define MAX_FASTF
Definition: defines.h:340
#define RT_CK_REGION(_p)
Definition: raytrace.h:559
#define HIDDEN
Definition: common.h:86
HIDDEN void tthrm_print(register struct region *rp, void *dp)
Definition: sh_treetherm.c:460
if(share_geom)
Definition: nmg_mod.c:3829
#define RT_AP_CHECK(_ap)
Definition: raytrace.h:1685
HIDDEN int tthrm_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *mfp, struct rt_i *rtip)
Definition: sh_treetherm.c:220
#define OP_SUBTRACT
Binary: L subtract R.
Definition: raytrace.h:1129
float vect[NUM_NODES][3]
Definition: sh_treetherm.c:108
#define BU_CK_VLS(_vp)
Definition: vls.h:69
struct resource rt_uniresource
default. Defined in librt/globals.c
Definition: globals.c:41
#define OP_INTERSECT
Binary: L intersect R.
Definition: raytrace.h:1128
#define OP_DB_LEAF
Leaf of combination, db fmt.
Definition: raytrace.h:1139
void bn_mat_print(const char *title, const mat_t m)
Definition: mat.c:81
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
#define RT_CHECK_RTI(_p)
Definition: raytrace.h:1832
#define V3ARGS(a)
Definition: color.c:56
float node[NUM_NODES][3]
Definition: sh_treetherm.c:107
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
struct seg * pt_inseg
IN seg ptr (gives stp)
Definition: raytrace.h:576
double bs_length
Definition: sh_treetherm.c:92
#define OP_REGION
Leaf: tr_stp -> combined_tree_state.
Definition: raytrace.h:1131
void tree_parse(struct bu_list *br, union tree *tr)
Definition: sh_treetherm.c:185
struct tree::tree_node tr_b
#define UNUSED(parameter)
Definition: common.h:239
double bs_dist
Definition: sh_treetherm.c:95
struct mfuncs tthrm_mfuncs[]
Definition: sh_treetherm.c:159
#define OP_GUARD
Unary: not L, or else!
Definition: raytrace.h:1135
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
struct bu_mapped_file * bu_open_mapped_file(const char *name, const char *appl)
Definition: mappedfile.c:56
struct branch_seg * bs_prev
Definition: sh_treetherm.c:88
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
uint32_t magic
Definition: sh_treetherm.c:104
#define BU_STRUCTPARSE_FUNC_NULL
Definition: parse.h:153
struct bu_structparse tthrm_parse[]
Definition: sh_treetherm.c:138
HIDDEN int tthrm_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
Definition: sh_treetherm.c:528
float * bs_nodes[4]
Definition: sh_treetherm.c:96
int db_region_mat(mat_t m, struct db_i *dbip, const char *name, struct resource *resp)
Definition: db_tree.c:2269
double bs_sradius
Definition: sh_treetherm.c:93
float dir[3]
Definition: sh_treetherm.c:106
#define ZERO(val)
Definition: units.c:38
#define RDEBUG_SHADE
Definition: optical.h:130
vect_t bs_dir
Definition: sh_treetherm.c:91
struct db_i * rti_dbip
prt to Database instance struct
Definition: raytrace.h:1774
fastf_t tt_min_temp
Definition: sh_treetherm.c:121
#define CYL_DATA(_n)
int bu_struct_parse(const struct bu_vls *in_vls, const struct bu_structparse *desc, const char *base, void *data)
Definition: parse.c:878
struct branch_seg * bs_next
Definition: sh_treetherm.c:87
#define CK_tthrm_SP(_p)
Definition: sh_treetherm.c:39
point_t bs_start
Definition: sh_treetherm.c:90
void * st_specific
-> ID-specific (private) struct
Definition: raytrace.h:435
#define tthrm_MAGIC
Definition: sh_treetherm.c:38
void build_tree(struct bu_list *br, struct region *rp)
Definition: sh_treetherm.c:208
void bu_close_mapped_file(struct bu_mapped_file *mp)
Definition: mappedfile.c:339
union tree * reg_treetop
Pointer to boolean tree.
Definition: raytrace.h:540
HIDDEN void tthrm_free(void *cp)
Definition: sh_treetherm.c:470
uint32_t magic
Definition: sh_treetherm.c:118
float pt[3]
Definition: sh_treetherm.c:105
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
struct thrm_seg * tt_segs
Definition: sh_treetherm.c:125
double bs_eradius
Definition: sh_treetherm.c:94
#define OP_SOLID
Leaf: tr_stp -> solid.
Definition: raytrace.h:1126
int st_id
Solid ident.
Definition: raytrace.h:431
#define RT_CHECK_PT(_p)
compat
Definition: raytrace.h:588
struct bu_list * tt_br
Definition: sh_treetherm.c:124
Definition: vls.h:56
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
double fastf_t
Definition: defines.h:300
#define OP_UNION
Binary: L union R.
Definition: raytrace.h:1127
Header file for the BRL-CAD Optical Library, LIBOPTICAL.
#define CK_THRM_SEG(_p)
Definition: sh_treetherm.c:102
#define OP_NOT
Unary: not L.
Definition: raytrace.h:1134
int rdebug
Definition: init.c:39
void print_thrm_seg(struct thrm_seg *ts)
Definition: sh_treetherm.c:164
struct bu_list bs_siblings
Definition: sh_treetherm.c:86