BRL-CAD
rt.c
Go to the documentation of this file.
1 /* R T . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2008-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 libged/rt.c
21  *
22  * The rt command.
23  *
24  */
25 
26 #include "common.h"
27 
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34 
35 #ifdef HAVE_SYS_WAIT_H
36 # include <sys/wait.h>
37 #endif
38 
39 
40 #include "tcl.h"
41 #include "bu/cmd.h"
42 
43 
44 #include "./ged_private.h"
45 
46 
48  struct ged_run_rt *rrtp;
49  struct ged *gedp;
50 };
51 
52 
53 void
54 _ged_rt_write(struct ged *gedp,
55  FILE *fp,
56  vect_t eye_model)
57 {
58  quat_t quat;
59 
60  /* Double-precision IEEE floating point only guarantees 15-17
61  * digits of precision; single-precision only 6-9 significant
62  * decimal digits. Using a %.15e precision specifier makes our
63  * printed value dip into unreliable territory (1+15 digits).
64  * Looking through our history, %.14e seems to be safe as the
65  * value prior to printing quaternions was %.9e, although anything
66  * from 9->14 "should" be safe as it's above our calculation
67  * tolerance and above single-precision capability.
68  */
69  fprintf(fp, "viewsize %.14e;\n", gedp->ged_gvp->gv_size);
70  quat_mat2quat(quat, gedp->ged_gvp->gv_rotation);
71  fprintf(fp, "orientation %.14e %.14e %.14e %.14e;\n", V4ARGS(quat));
72  fprintf(fp, "eye_pt %.14e %.14e %.14e;\n",
73  eye_model[X], eye_model[Y], eye_model[Z]);
74 
75  fprintf(fp, "start 0; clean;\n");
76 
78 
80 
82 
83  fprintf(fp, "end;\n");
84 }
85 
86 
87 void
89  vect_t eye_model)
90 {
91  if (gedp->ged_gvp->gv_zclip || gedp->ged_gvp->gv_perspective > 0) {
92  vect_t temp;
93 
94  VSET(temp, 0.0, 0.0, 1.0);
95  MAT4X3PNT(eye_model, gedp->ged_gvp->gv_view2model, temp);
96  } else {
97  /* not doing zclipping, so back out of geometry */
98  int i;
99  vect_t direction;
100  vect_t extremum[2];
101  double t_in;
102  vect_t diag1;
103  vect_t diag2;
104  point_t ecenter;
105 
106  VSET(eye_model, -gedp->ged_gvp->gv_center[MDX],
107  -gedp->ged_gvp->gv_center[MDY], -gedp->ged_gvp->gv_center[MDZ]);
108 
109  for (i = 0; i < 3; ++i) {
110  extremum[0][i] = INFINITY;
111  extremum[1][i] = -INFINITY;
112  }
113 
114  (void)dl_bounding_sph(gedp->ged_gdp->gd_headDisplay, &(extremum[0]), &(extremum[1]), 1);
115 
116  VMOVEN(direction, gedp->ged_gvp->gv_rotation + 8, 3);
117  for (i = 0; i < 3; ++i)
118  if (NEAR_ZERO(direction[i], 1e-10))
119  direction[i] = 0.0;
120 
121  VSUB2(diag1, extremum[1], extremum[0]);
122  VADD2(ecenter, extremum[1], extremum[0]);
123  VSCALE(ecenter, ecenter, 0.5);
124  VSUB2(diag2, ecenter, eye_model);
125  t_in = MAGNITUDE(diag1) + MAGNITUDE(diag2);
126  VJOIN1(eye_model, eye_model, t_in, direction);
127  }
128 }
129 
130 
131 void
132 _ged_rt_output_handler(ClientData clientData, int UNUSED(mask))
133 {
134  struct _ged_rt_client_data *drcdp = (struct _ged_rt_client_data *)clientData;
135  struct ged_run_rt *run_rtp;
136 #ifndef _WIN32
137  int count = 0;
138 #else
139  DWORD count = 0;
140 #endif
141  int read_failed = 0;
142  char line[RT_MAXLINE+1] = {0};
143 
144  if (drcdp == (struct _ged_rt_client_data *)NULL ||
145  drcdp->gedp == (struct ged *)NULL ||
146  drcdp->rrtp == (struct ged_run_rt *)NULL ||
147  brlcad_interp == (Tcl_Interp *)NULL)
148  return;
149 
150  run_rtp = drcdp->rrtp;
151 
152  /* Get data from rt */
153 #ifndef _WIN32
154  count = read((int)run_rtp->fd, line, RT_MAXLINE);
155  if (count <= 0) {
156  read_failed = 1;
157  }
158 #else
159  if (Tcl_Eof(run_rtp->chan) ||
160  (!ReadFile(run_rtp->fd, line, RT_MAXLINE, &count, 0))) {
161  read_failed = 1;
162  }
163 #endif
164 
165  /* sanity clamping */
166  if (count < 0) {
167  perror("READ ERROR");
168  count = 0;
169  } else if (count > RT_MAXLINE) {
170  count = RT_MAXLINE;
171  }
172 
173  if (read_failed) {
174  int aborted;
175 
176  /* was it aborted? */
177 #ifndef _WIN32
178  int rpid;
179  int retcode = 0;
180 
181  Tcl_DeleteFileHandler(run_rtp->fd);
182  close(run_rtp->fd);
183 
184  /* wait for the forked process */
185  while ((rpid = wait(&retcode)) != run_rtp->pid && rpid != -1);
186 
187  aborted = run_rtp->aborted;
188 #else
189  DWORD retcode = 0;
190  Tcl_DeleteChannelHandler(run_rtp->chan,
192  (ClientData)drcdp);
193  Tcl_Close(brlcad_interp, run_rtp->chan);
194 
195  /* wait for the forked process
196  * either EOF has been sent or there was a read error.
197  * there is no need to block indefinitely
198  */
199  WaitForSingleObject(run_rtp->hProcess, 120);
200  /* !!! need to observe implications of being non-infinite
201  * WaitForSingleObject(run_rtp->hProcess, INFINITE);
202  */
203 
204  if (GetLastError() == ERROR_PROCESS_ABORTED) {
205  run_rtp->aborted = 1;
206  }
207 
208  GetExitCodeProcess(run_rtp->hProcess, &retcode);
209  /* may be useful to try pr_wait_status() here */
210 
211  aborted = run_rtp->aborted;
212 #endif
213 
214  if (aborted)
215  bu_log("Raytrace aborted.\n");
216  else if (retcode)
217  bu_log("Raytrace failed.\n");
218  else
219  bu_log("Raytrace complete.\n");
220 
221  if (drcdp->gedp->ged_gdp->gd_rtCmdNotify != (void (*)(int))0)
222  drcdp->gedp->ged_gdp->gd_rtCmdNotify(aborted);
223 
224  /* free run_rtp */
225  BU_LIST_DEQUEUE(&run_rtp->l);
226  BU_PUT(run_rtp, struct ged_run_rt);
227  BU_PUT(drcdp, struct _ged_rt_client_data);
228 
229  return;
230  }
231 
232  /* for feelgoodedness */
233  line[count] = '\0';
234 
235  /* handle (i.e., probably log to stderr) the resulting line */
236  if (drcdp->gedp->ged_output_handler != (void (*)(struct ged *, char *))0)
237  drcdp->gedp->ged_output_handler(drcdp->gedp, line);
238  else
239  bu_vls_printf(drcdp->gedp->ged_result_str, "%s", line);
240 }
241 
242 
243 int
244 _ged_run_rt(struct ged *gedp)
245 {
246  int i;
247  FILE *fp_in;
248 #ifndef _WIN32
249  int pipe_in[2];
250  int pipe_err[2];
251 #else
252  HANDLE pipe_in[2], pipe_inDup;
253  HANDLE pipe_err[2], pipe_errDup;
254  STARTUPINFO si = {0};
255  PROCESS_INFORMATION pi = {0};
256  SECURITY_ATTRIBUTES sa = {0};
257  struct bu_vls line = BU_VLS_INIT_ZERO;
258 #endif
259  vect_t eye_model;
260  struct ged_run_rt *run_rtp;
261  struct _ged_rt_client_data *drcdp;
262 #ifndef _WIN32
263  int pid;
264  int ret;
265 
266  ret = pipe(pipe_in);
267  if (ret < 0)
268  perror("pipe");
269  ret = pipe(pipe_err);
270  if (ret < 0)
271  perror("pipe");
272 
273  if ((pid = fork()) == 0) {
274  /* make this a process group leader */
275  setpgid(0, 0);
276 
277  /* Redirect stdin and stderr */
278  (void)close(0);
279  ret = dup(pipe_in[0]);
280  if (ret < 0)
281  perror("dup");
282  (void)close(2);
283  ret = dup(pipe_err[1]);
284  if (ret < 0)
285  perror("dup");
286 
287  /* close pipes */
288  (void)close(pipe_in[0]);
289  (void)close(pipe_in[1]);
290  (void)close(pipe_err[0]);
291  (void)close(pipe_err[1]);
292 
293  for (i = 3; i < 20; i++)
294  (void)close(i);
295 
296  (void)execvp(gedp->ged_gdp->gd_rt_cmd[0], gedp->ged_gdp->gd_rt_cmd);
297  perror(gedp->ged_gdp->gd_rt_cmd[0]);
298  exit(16);
299  }
300 
301  /* As parent, send view information down pipe */
302  (void)close(pipe_in[0]);
303  fp_in = fdopen(pipe_in[1], "w");
304 
305  (void)close(pipe_err[1]);
306 
307  _ged_rt_set_eye_model(gedp, eye_model);
308  _ged_rt_write(gedp, fp_in, eye_model);
309  (void)fclose(fp_in);
310 
311  BU_GET(run_rtp, struct ged_run_rt);
312  BU_LIST_INIT(&run_rtp->l);
313  BU_LIST_APPEND(&gedp->ged_gdp->gd_headRunRt.l, &run_rtp->l);
314 
315  run_rtp->fd = pipe_err[0];
316  run_rtp->pid = pid;
317 
318  BU_GET(drcdp, struct _ged_rt_client_data);
319  drcdp->gedp = gedp;
320  drcdp->rrtp = run_rtp;
321 
322  Tcl_CreateFileHandler(run_rtp->fd,
323  TCL_READABLE,
325  (ClientData)drcdp);
326 
327  return 0;
328 
329 #else
330  sa.nLength = sizeof(sa);
331  sa.bInheritHandle = TRUE;
332  sa.lpSecurityDescriptor = NULL;
333 
334  /* Create a pipe for the child process's STDOUT. */
335  CreatePipe(&pipe_err[0], &pipe_err[1], &sa, 0);
336 
337  /* Create noninheritable read handle and close the inheritable read handle. */
338  DuplicateHandle(GetCurrentProcess(), pipe_err[0],
339  GetCurrentProcess(), &pipe_errDup ,
340  0, FALSE,
341  DUPLICATE_SAME_ACCESS);
342  CloseHandle(pipe_err[0]);
343 
344  /* Create a pipe for the child process's STDIN. */
345  CreatePipe(&pipe_in[0], &pipe_in[1], &sa, 0);
346 
347  /* Duplicate the write handle to the pipe so it is not inherited. */
348  DuplicateHandle(GetCurrentProcess(), pipe_in[1],
349  GetCurrentProcess(), &pipe_inDup,
350  0, FALSE, /* not inherited */
351  DUPLICATE_SAME_ACCESS);
352  CloseHandle(pipe_in[1]);
353 
354 
355  si.cb = sizeof(STARTUPINFO);
356  si.lpReserved = NULL;
357  si.lpReserved2 = NULL;
358  si.cbReserved2 = 0;
359  si.lpDesktop = NULL;
360  si.dwFlags = STARTF_USESTDHANDLES;
361  si.hStdInput = pipe_in[0];
362  si.hStdOutput = pipe_err[1];
363  si.hStdError = pipe_err[1];
364 
365  for (i = 0; i < gedp->ged_gdp->gd_rt_cmd_len; i++) {
366  bu_vls_printf(&line, "%s ", gedp->ged_gdp->gd_rt_cmd[i]);
367  }
368 
369  CreateProcess(NULL, bu_vls_addr(&line), NULL, NULL, TRUE,
370  DETACHED_PROCESS, NULL, NULL,
371  &si, &pi);
372  bu_vls_free(&line);
373 
374  CloseHandle(pipe_in[0]);
375  CloseHandle(pipe_err[1]);
376 
377  /* As parent, send view information down pipe */
378  fp_in = _fdopen(_open_osfhandle((intptr_t)pipe_inDup, _O_TEXT), "wb");
379 
380  _ged_rt_set_eye_model(gedp, eye_model);
381  _ged_rt_write(gedp, fp_in, eye_model);
382  (void)fclose(fp_in);
383 
384  BU_GET(run_rtp, struct ged_run_rt);
385  BU_LIST_INIT(&run_rtp->l);
386  BU_LIST_APPEND(&gedp->ged_gdp->gd_headRunRt.l, &run_rtp->l);
387 
388  run_rtp->fd = pipe_errDup;
389  run_rtp->hProcess = pi.hProcess;
390  run_rtp->pid = pi.dwProcessId;
391  run_rtp->aborted=0;
392  run_rtp->chan = Tcl_MakeFileChannel(run_rtp->fd, TCL_READABLE);
393 
394  BU_GET(drcdp, struct _ged_rt_client_data);
395  drcdp->gedp = gedp;
396  drcdp->rrtp = run_rtp;
397 
398  Tcl_CreateChannelHandler(run_rtp->chan,
399  TCL_READABLE,
401  (ClientData)drcdp);
402 
403  return 0;
404 #endif
405 }
406 
407 
408 size_t
410 {
411  struct display_list *gdlp = NULL;
412  size_t visibleCount = 0;
413  for (BU_LIST_FOR(gdlp, display_list, gedp->ged_gdp->gd_headDisplay)) {
414  visibleCount++;
415  }
416  return visibleCount;
417 }
418 
419 
420 /**
421  * Build a command line vector of the tops of all objects in view.
422  */
423 int
424 ged_build_tops(struct ged *gedp, char **start, char **end)
425 {
426  struct display_list *gdlp;
427  char **vp = start;
428 
429  for (BU_LIST_FOR(gdlp, display_list, gedp->ged_gdp->gd_headDisplay)) {
430  if (((struct directory *)gdlp->dl_dp)->d_addr == RT_DIR_PHONY_ADDR)
431  continue;
432 
433  if ((vp != NULL) && (vp < end))
434  *vp++ = bu_strdup(bu_vls_addr(&gdlp->dl_path));
435  else {
436  bu_vls_printf(gedp->ged_result_str, "libged: ran out of command vector space at %s\n", ((struct directory *)gdlp->dl_dp)->d_namep);
437  break;
438  }
439  }
440 
441  if ((vp != NULL) && (vp < end)) {
442  *vp = (char *) 0;
443  }
444 
445  return vp-start;
446 }
447 
448 
449 int
450 ged_rt(struct ged *gedp, int argc, const char *argv[])
451 {
452  char **vp;
453  int i;
454  int units_supplied = 0;
455  char pstring[32];
456  int args;
457 
458  const char *bin;
459  char rt[256] = {0};
460 
463  GED_CHECK_VIEW(gedp, GED_ERROR);
464  GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
465 
466  /* initialize result */
467  bu_vls_trunc(gedp->ged_result_str, 0);
468 
469  args = argc + 7 + 2 + ged_count_tops(gedp);
470  gedp->ged_gdp->gd_rt_cmd = (char **)bu_calloc(args, sizeof(char *), "alloc gd_rt_cmd");
471 
472  bin = bu_brlcad_root("bin", 1);
473  if (bin) {
474 #ifdef _WIN32
475  snprintf(rt, 256, "\"%s/%s\"", bin, argv[0]);
476 #else
477  snprintf(rt, 256, "%s/%s", bin, argv[0]);
478 #endif
479  }
480 
481  vp = &gedp->ged_gdp->gd_rt_cmd[0];
482  *vp++ = rt;
483  *vp++ = "-M";
484 
485  if (gedp->ged_gvp->gv_perspective > 0) {
486  (void)sprintf(pstring, "-p%g", gedp->ged_gvp->gv_perspective);
487  *vp++ = pstring;
488  }
489 
490  for (i = 1; i < argc; i++) {
491  if (argv[i][0] == '-' && argv[i][1] == 'u' &&
492  BU_STR_EQUAL(argv[1], "-u")) {
493  units_supplied=1;
494  } else if (argv[i][0] == '-' && argv[i][1] == '-' &&
495  argv[i][2] == '\0') {
496  ++i;
497  break;
498  }
499  *vp++ = (char *)argv[i];
500  }
501 
502  /* default to local units when not specified on command line */
503  if (!units_supplied) {
504  *vp++ = "-u";
505  *vp++ = "model";
506  }
507 
508  /* XXX why is this different for win32 only? */
509 #ifdef _WIN32
510  {
511  char buf[512];
512 
513  snprintf(buf, 512, "\"%s\"", gedp->ged_wdbp->dbip->dbi_filename);
514  *vp++ = buf;
515  }
516 #else
517  *vp++ = gedp->ged_wdbp->dbip->dbi_filename;
518 #endif
519 
520  /*
521  * Now that we've grabbed all the options, if no args remain,
522  * append the names of all stuff currently displayed.
523  * Otherwise, simply append the remaining args.
524  */
525  if (i == argc) {
526  gedp->ged_gdp->gd_rt_cmd_len = vp - gedp->ged_gdp->gd_rt_cmd;
527  gedp->ged_gdp->gd_rt_cmd_len += ged_build_tops(gedp, vp, &gedp->ged_gdp->gd_rt_cmd[args]);
528  } else {
529  while (i < argc)
530  *vp++ = (char *)argv[i++];
531  *vp = 0;
532  vp = &gedp->ged_gdp->gd_rt_cmd[0];
533  while (*vp)
534  bu_vls_printf(gedp->ged_result_str, "%s ", *vp++);
535 
536  bu_vls_printf(gedp->ged_result_str, "\n");
537  }
538  (void)_ged_run_rt(gedp);
539  bu_free(gedp->ged_gdp->gd_rt_cmd, "free gd_rt_cmd");
540  gedp->ged_gdp->gd_rt_cmd = NULL;
541 
542  return GED_OK;
543 }
544 
545 
546 /*
547  * Local Variables:
548  * tab-width: 8
549  * mode: C
550  * indent-tabs-mode: t
551  * c-file-style: "stroustrup"
552  * End:
553  * ex: shiftwidth=4 tabstop=8
554  */
#define GED_OK
Definition: ged.h:55
#define BU_LIST_FOR(p, structure, hp)
Definition: list.h:365
#define FALSE
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
mat_t gv_center
Definition: bview.h:221
void dl_write_animate(struct bu_list *hdlp, FILE *fp)
int ged_build_tops(struct ged *gedp, char **start, char **end)
Definition: rt.c:424
int _ged_run_rt(struct ged *gedp)
Definition: rt.c:244
Definition: ged.h:338
struct db_i * dbip
Definition: raytrace.h:1266
#define RT_MAXLINE
Definition: raytrace.h:1255
#define VSET(a, b, c, d)
Definition: color.c:53
struct ged_run_rt * rrtp
Definition: rt.c:48
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
#define GED_CHECK_ARGC_GT_0(_gedp, _argc, _flags)
Definition: ged.h:202
struct ged_run_rt gd_headRunRt
head of forked rt processes
Definition: ged.h:314
int fd
Definition: ged.h:272
struct rt_wdb * ged_wdbp
Definition: ged.h:340
Header file for the BRL-CAD common definitions.
fastf_t gv_perspective
perspective angle
Definition: bview.h:214
void * dl_dp
Definition: bview.h:47
#define BU_LIST_APPEND(old, new)
Definition: list.h:197
struct bu_list * gd_headDisplay
head of display list
Definition: ged.h:307
#define GED_ERROR
Definition: ged.h:61
struct bview * ged_gvp
Definition: ged.h:361
mat_t gv_view2model
Definition: bview.h:224
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
struct bu_list l
Definition: ged.h:260
Definition: color.c:49
void _ged_rt_set_eye_model(struct ged *gedp, vect_t eye_model)
Definition: rt.c:88
#define GED_CHECK_VIEW(_gedp, _flags)
Definition: ged.h:140
#define GED_CHECK_DATABASE_OPEN(_gedp, _flags)
Definition: ged.h:114
int gd_rt_cmd_len
Definition: ged.h:313
FILE * fdopen(int, const char *)
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
fastf_t gv_size
2.0 * scale
Definition: bview.h:212
size_t ged_count_tops(struct ged *gedp)
Definition: rt.c:409
#define NEAR_ZERO(val, epsilon)
Definition: color.c:55
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
#define RT_DIR_PHONY_ADDR
Special marker for d_addr field.
Definition: raytrace.h:879
char ** gd_rt_cmd
Definition: ged.h:312
#define GED_CHECK_DRAWABLE(_gedp, _flags)
Definition: ged.h:129
int dl_bounding_sph(struct bu_list *hdlp, vect_t *min, vect_t *max, int pflag)
Definition: display_list.c:157
#define UNUSED(parameter)
Definition: common.h:239
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
struct bu_vls dl_path
Definition: bview.h:48
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
struct bu_vls * ged_result_str
Definition: ged.h:357
struct ged_drawable * ged_gdp
Definition: ged.h:360
struct ged * gedp
Definition: rt.c:49
mat_t gv_rotation
Definition: bview.h:220
void _ged_rt_output_handler(ClientData clientData, int mask)
Definition: rt.c:132
#define BU_LIST_INIT(_hp)
Definition: list.h:148
int aborted
Definition: ged.h:275
HIDDEN fastf_t bin(fastf_t val, fastf_t step)
Definition: nmg_tri_mc.c:461
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
void(* ged_output_handler)(struct ged *, char *)
function for handling output
Definition: ged.h:368
Definition: color.c:51
void _ged_rt_write(struct ged *gedp, FILE *fp, vect_t eye_model)
Definition: rt.c:54
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
void quat_mat2quat(quat_t quat, const mat_t mat)
Quaternion math routines.
#define RT_DIR_USED
One bit, used similar to d_nref.
Definition: raytrace.h:888
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
int gv_zclip
Definition: bview.h:235
int pid
Definition: ged.h:273
#define BU_LIST_DEQUEUE(cur)
Definition: list.h:209
const char * bu_brlcad_root(const char *rhs, int fail_quietly)
Definition: brlcad_path.c:292
Definition: vls.h:56
char * dbi_filename
file name
Definition: raytrace.h:805
Tcl_Interp * brlcad_interp
Definition: tcl.c:41
#define TRUE
int ged_rt(struct ged *gedp, int argc, const char *argv[])
Definition: rt.c:450
void dl_bitwise_and_fullpath(struct bu_list *hdlp, int flag_val)
Definition: color.c:50
#define bu_strdup(s)
Definition: str.h:71
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126