BRL-CAD
bot_dump.c
Go to the documentation of this file.
1 /* B O T _ D U M P . 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/bot_dump.c
21  *
22  * The bot_dump command.
23  *
24  */
25 
26 #include "common.h"
27 
28 #include <stdlib.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include "bnetwork.h"
34 
35 #include "bu/cv.h"
36 #include "bu/getopt.h"
37 #include "bu/units.h"
38 #include "vmath.h"
39 #include "nmg.h"
40 #include "rtgeom.h"
41 
42 #include "dm/bview.h"
43 
44 #include "raytrace.h"
45 #include "wdb.h"
46 
47 #include "brlcad_version.h"
48 
49 #include "mater.h"
50 
51 #include "obj.h"
52 
53 #include "./ged_private.h"
54 
55 
56 #define V3ARGS_SCALE(_a) (_a)[X]*cfactor, (_a)[Y]*cfactor, (_a)[Z]*cfactor
57 
58 static char usage[] = "\
59 Usage: %s [-b] [-n] [-m directory] [-o file] [-t dxf|obj|sat|stl] [-u units] [bot1 bot2 ...]\n";
60 
61 
63  struct ged *gedp;
64  FILE *fp;
65  int fd;
66  char *file_ext;
67 };
68 
69 
71  struct bu_list l;
72  struct bu_vls name;
73  unsigned char r;
74  unsigned char g;
75  unsigned char b;
77 };
78 
79 
80 static int using_dbot_dump;
89 
90 static enum otype output_type;
91 static int binary;
92 static int normals;
93 static fastf_t cfactor;
94 static char *output_file; /* output filename */
95 static char *output_directory; /* directory name to hold output files */
96 static unsigned int total_faces;
97 static int v_offset;
98 static int curr_line_num;
99 
100 static int curr_body_id;
101 static int curr_lump_id;
102 static int curr_shell_id;
103 static int curr_face_id;
104 static int curr_loop_id;
105 static int curr_edge_id;
106 
107 /* Byte swaps a four byte value */
108 static void
109 lswap(unsigned int *v)
110 {
111  unsigned int r;
112 
113  r =*v;
114  *v = ((r & 0xff) << 24) | ((r & 0xff00) << 8) | ((r & 0xff0000) >> 8)
115  | ((r & 0xff000000) >> 24);
116 }
117 
118 
119 static struct _ged_obj_material *
120 obj_get_material(int red, int green, int blue, fastf_t transparency)
121 {
122  struct _ged_obj_material *gomp;
123 
124  for (BU_LIST_FOR(gomp, _ged_obj_material, &HeadObjMaterials)) {
125  if (gomp->r == red &&
126  gomp->g == green &&
127  gomp->b == blue &&
128  ZERO(gomp->a - transparency)) {
129  return gomp;
130  }
131  }
132 
133  BU_GET(gomp, struct _ged_obj_material);
134  BU_LIST_APPEND(&HeadObjMaterials, &gomp->l);
135  gomp->r = red;
136  gomp->g = green;
137  gomp->b = blue;
138  gomp->a = transparency;
139  bu_vls_init(&gomp->name);
140  bu_vls_printf(&gomp->name, "matl_%d", ++num_obj_materials);
141 
142  /* Write out newmtl to mtl file */
143  fprintf(obj_materials_fp, "newmtl %s\n", bu_vls_addr(&gomp->name));
144  fprintf(obj_materials_fp, "Kd %f %f %f\n",
145  (fastf_t)gomp->r / 255.0,
146  (fastf_t)gomp->g / 255.0,
147  (fastf_t)gomp->b / 255.0);
148  fprintf(obj_materials_fp, "d %f\n", gomp->a);
149  fprintf(obj_materials_fp, "illum 1\n");
150 
151  return gomp;
152 }
153 
154 
155 static void
156 obj_free_materials() {
157  struct _ged_obj_material *gomp;
158 
159  while (BU_LIST_WHILE(gomp, _ged_obj_material, &HeadObjMaterials)) {
160  BU_LIST_DEQUEUE(&gomp->l);
161  bu_vls_free(&gomp->name);
162  BU_PUT(gomp, struct _ged_obj_material);
163  }
164 }
165 
166 
167 static void
168 sat_write_header(FILE *fp)
169 {
170  time_t now;
171 
172  /* SAT header consists of three lines:
173  *
174  * 1: SAT_version num_records num_objects history_boolean
175  * 2: strlen product_id_str strlen version_str strlen date_str
176  * 3: cnv_to_mm resabs_value resnor_value
177  *
178  * When num_records is zero, it looks for an end marker.
179  */
180  fprintf(fp, "400 0 1 0\n");
181 
182  time(&now);
183  fprintf(fp, "%ld BRL-CAD(%s)-bot_dump 16 ACIS 8.0 Unknown %ld %s",
184  (long)strlen(brlcad_version())+18, brlcad_version(), (long)strlen(ctime(&now)) - 1, ctime(&now));
185 
186  /* FIXME: this includes abs tolerance info, should probably output ours */
187  fprintf(fp, "1 9.9999999999999995e-007 1e-010\n");
188 }
189 
190 
191 static void
192 sat_write_bot(struct rt_bot_internal *bot, FILE *fp, char *UNUSED(name))
193 {
194  int i, j;
195  fastf_t *vertices;
196  int *faces;
197  int first_vertex;
198  int first_coedge;
199  int first_face;
200  int num_vertices = bot->num_vertices;
201  int num_faces = bot->num_faces;
202 
203  vertices = bot->vertices;
204  faces = bot->faces;
205 
206  curr_body_id = curr_line_num;
207  curr_lump_id = curr_body_id + 1;
208  curr_shell_id = curr_lump_id + 1;
209  curr_face_id = curr_shell_id + 1 + num_vertices*2 + num_faces*6;
210 
211  fprintf(fp, "-%d body $-1 $%d $-1 $-1 #\n", curr_body_id, curr_lump_id);
212  fprintf(fp, "-%d lump $-1 $-1 $%d $%d #\n", curr_lump_id, curr_shell_id, curr_body_id);
213  fprintf(fp, "-%d shell $-1 $-1 $-1 $%d $-1 $%d #\n", curr_shell_id, curr_face_id, curr_lump_id);
214 
215  curr_line_num += 3;
216 
217  /* Dump out vertices */
218  first_vertex = curr_line_num;
219  for (i = 0; i < num_vertices; i++) {
220  curr_edge_id = -1;
221  for (j = 0; j < num_faces; j++) {
222  if (faces[3*j]+first_vertex == curr_line_num) {
223  curr_edge_id = first_vertex + num_vertices*2 + num_faces*3 + j*3;
224  break;
225  } else if (faces[3*j+1]+first_vertex == curr_line_num) {
226  curr_edge_id = first_vertex + num_vertices*2 + num_faces*3 + j*3 + 1;
227  break;
228  } else if (faces[3*j+2]+first_vertex == curr_line_num) {
229  curr_edge_id = first_vertex + num_vertices*2 + num_faces*3 + j*3 + 2;
230  break;
231  }
232  }
233 
234  fprintf(fp, "-%d vertex $-1 $%d $%d #\n", curr_line_num, curr_edge_id, curr_line_num+num_vertices);
235  ++curr_line_num;
236  }
237 
238  /* Dump out points */
239  for (i = 0; i < num_vertices; i++) {
240  fprintf(fp, "-%d point $-1 %f %f %f #\n", curr_line_num, V3ARGS_SCALE(&vertices[3*i]));
241  ++curr_line_num;
242  }
243 
244  /* Dump out coedges */
245  first_coedge = curr_line_num;
246  curr_loop_id = first_coedge+num_faces*7;
247  for (i = 0; i < num_faces; i++) {
248  fprintf(fp, "-%d coedge $-1 $%d $%d $%d $%d forward $%d $-1 #\n",
249  curr_line_num, curr_line_num+1, curr_line_num+2, curr_line_num,
250  curr_line_num+num_faces*3, curr_loop_id);
251  ++curr_line_num;
252  fprintf(fp, "-%d coedge $-1 $%d $%d $%d $%d forward $%d $-1 #\n",
253  curr_line_num, curr_line_num+1, curr_line_num-1, curr_line_num,
254  curr_line_num+num_faces*3, curr_loop_id);
255  ++curr_line_num;
256  fprintf(fp, "-%d coedge $-1 $%d $%d $%d $%d forward $%d $-1 #\n",
257  curr_line_num, curr_line_num-2, curr_line_num-1, curr_line_num,
258  curr_line_num+num_faces*3, curr_loop_id);
259  ++curr_line_num;
260  ++curr_loop_id;
261  }
262 
263  /* Dump out edges */
264  for (i = 0; i < num_faces; i++) {
265  fprintf(fp, "-%d edge $-1 $%d $%d $%d $%d forward #\n", curr_line_num,
266  faces[3*i]+first_vertex, faces[3*i+1]+first_vertex,
267  first_coedge + i*3, curr_line_num + num_faces*5);
268  ++curr_line_num;
269  fprintf(fp, "-%d edge $-1 $%d $%d $%d $%d forward #\n", curr_line_num,
270  faces[3*i+1]+first_vertex, faces[3*i+2]+first_vertex,
271  first_coedge + i*3 + 1, curr_line_num + num_faces*5);
272  ++curr_line_num;
273  fprintf(fp, "-%d edge $-1 $%d $%d $%d $%d forward #\n", curr_line_num,
274  faces[3*i+2]+first_vertex, faces[3*i]+first_vertex,
275  first_coedge + i*3 + 2, curr_line_num + num_faces*5);
276  ++curr_line_num;
277  }
278 
279  /* Dump out faces */
280  first_face = curr_line_num;
281  for (i = 0; i < num_faces-1; i++) {
282  fprintf(fp, "-%d face $-1 $%d $%d $%d $-1 $%d forward single #\n",
283  curr_line_num, curr_line_num+1, curr_line_num+num_faces,
284  curr_shell_id, curr_line_num + num_faces*5);
285  ++curr_line_num;
286  }
287  fprintf(fp, "-%d face $-1 $-1 $%d $%d $-1 $%d forward single #\n",
288  curr_line_num, curr_line_num+num_faces, curr_shell_id,
289  curr_line_num + num_faces*5);
290  ++curr_line_num;
291 
292  /* Dump out loops */
293  for (i = 0; i < num_faces; i++) {
294  fprintf(fp, "-%d loop $-1 $-1 $%d $%d #\n",
295  curr_line_num, first_coedge+i*3, first_face+i);
296  ++curr_line_num;
297  }
298 
299  /* Dump out straight-curves for each edge */
300  for (i = 0; i < num_faces; i++) {
301  point_t A;
302  point_t B;
303  point_t C;
304  vect_t BmA;
305  vect_t CmB;
306  vect_t AmC;
307  int vi;
308 
309  vi = 3*faces[3*i];
310  VSET(A, vertices[vi], vertices[vi+1], vertices[vi+2]);
311  vi = 3*faces[3*i+1];
312  VSET(B, vertices[vi], vertices[vi+1], vertices[vi+2]);
313  vi = 3*faces[3*i+2];
314  VSET(C, vertices[vi], vertices[vi+1], vertices[vi+2]);
315  VSUB2(BmA, B, A);
316  VSUB2(CmB, C, B);
317  VSUB2(AmC, A, C);
318  VUNITIZE(BmA);
319  VUNITIZE(CmB);
320  VUNITIZE(AmC);
321 
322  fprintf(fp, "-%d straight-curve $-1 %f %f %f %f %f %f I I #\n", curr_line_num, V3ARGS_SCALE(A), V3ARGS(BmA));
323  ++curr_line_num;
324  fprintf(fp, "-%d straight-curve $-1 %f %f %f %f %f %f I I #\n", curr_line_num, V3ARGS_SCALE(B), V3ARGS(CmB));
325  ++curr_line_num;
326  fprintf(fp, "-%d straight-curve $-1 %f %f %f %f %f %f I I #\n", curr_line_num, V3ARGS_SCALE(C), V3ARGS(AmC));
327  ++curr_line_num;
328  }
329 
330  /* Dump out plane-surfaces for each face */
331  for (i = 0; i < num_faces; i++) {
332  point_t A;
333  point_t B;
334  point_t C;
335  point_t center;
336  vect_t BmA;
337  vect_t CmA;
338  vect_t norm;
339  int vi;
340  fastf_t sf = 1.0/3.0;
341 
342  vi = 3*faces[3*i];
343  VSET(A, vertices[vi], vertices[vi+1], vertices[vi+2]);
344  vi = 3*faces[3*i+1];
345  VSET(B, vertices[vi], vertices[vi+1], vertices[vi+2]);
346  vi = 3*faces[3*i+2];
347  VSET(C, vertices[vi], vertices[vi+1], vertices[vi+2]);
348 
349  VADD3(center, A, B, C);
350  VSCALE(center, center, sf);
351 
352  VSUB2(BmA, B, A);
353  VSUB2(CmA, C, A);
354  if (bot->orientation != RT_BOT_CW) {
355  VCROSS(norm, BmA, CmA);
356  } else {
357  VCROSS(norm, CmA, BmA);
358  }
359  VUNITIZE(norm);
360 
361  VUNITIZE(BmA);
362 
363  fprintf(fp, "-%d plane-surface $-1 %f %f %f %f %f %f %f %f %f forward_v I I I I #\n",
364  curr_line_num, V3ARGS_SCALE(A), V3ARGS(norm), V3ARGS(BmA));
365 
366  ++curr_line_num;
367  }
368 }
369 
370 
371 static void
372 dxf_write_bot(struct rt_bot_internal *bot, FILE *fp, char *name)
373 {
374  fastf_t *vertices;
375  int num_faces, *faces;
376  point_t A;
377  point_t B;
378  point_t C;
379  int i, vi;
380 
381  vertices = bot->vertices;
382  num_faces = bot->num_faces;
383  faces = bot->faces;
384 
385  for (i = 0; i < num_faces; i++) {
386  vi = 3*faces[3*i];
387  VSET(A, vertices[vi], vertices[vi+1], vertices[vi+2]);
388  vi = 3*faces[3*i+1];
389  VSET(B, vertices[vi], vertices[vi+1], vertices[vi+2]);
390  vi = 3*faces[3*i+2];
391  VSET(C, vertices[vi], vertices[vi+1], vertices[vi+2]);
392 
393  VSCALE(A, A, cfactor);
394  VSCALE(B, B, cfactor);
395  VSCALE(C, C, cfactor);
396 
397  fprintf(fp, "0\n3DFACE\n8\n%s\n62\n7\n", name);
398  fprintf(fp, "%d\n%f\n%d\n%f\n%d\n%f\n",
399  10, A[X], 20, A[Y], 30, A[Z]);
400  fprintf(fp, "%d\n%f\n%d\n%f\n%d\n%f\n",
401  11, B[X], 21, B[Y], 31, B[Z]);
402  fprintf(fp, "%d\n%f\n%d\n%f\n%d\n%f\n",
403  12, C[X], 22, C[Y], 32, C[Z]);
404  fprintf(fp, "%d\n%f\n%d\n%f\n%d\n%f\n",
405  12, C[X], 22, C[Y], 32, C[Z]);
406  }
407 
408 }
409 
410 
411 static void
412 obj_write_bot(struct rt_bot_internal *bot, FILE *fp, char *name)
413 {
414  int num_vertices;
415  fastf_t *vertices;
416  int num_faces, *faces;
417  point_t A;
418  point_t B;
419  point_t C;
420  vect_t BmA;
421  vect_t CmA;
422  vect_t norm;
423  int i, vi;
424  struct _ged_obj_material *gomp;
425 
426  if (using_dbot_dump) {
427  gomp = obj_get_material(curr_obj_red,
431  fprintf(fp, "usemtl %s\n", bu_vls_addr(&gomp->name));
432  }
433 
434  num_vertices = bot->num_vertices;
435  vertices = bot->vertices;
436  num_faces = bot->num_faces;
437  faces = bot->faces;
438 
439  fprintf(fp, "g %s\n", name);
440 
441  for (i = 0; i < num_vertices; i++) {
442  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(&vertices[3*i]));
443  }
444 
445  if (normals) {
446  for (i = 0; i < num_faces; i++) {
447  vi = 3*faces[3*i];
448  VSET(A, vertices[vi], vertices[vi+1], vertices[vi+2]);
449  vi = 3*faces[3*i+1];
450  VSET(B, vertices[vi], vertices[vi+1], vertices[vi+2]);
451  vi = 3*faces[3*i+2];
452  VSET(C, vertices[vi], vertices[vi+1], vertices[vi+2]);
453 
454  VSUB2(BmA, B, A);
455  VSUB2(CmA, C, A);
456  if (bot->orientation != RT_BOT_CW) {
457  VCROSS(norm, BmA, CmA);
458  } else {
459  VCROSS(norm, CmA, BmA);
460  }
461  VUNITIZE(norm);
462 
463  fprintf(fp, "vn %f %f %f\n", V3ARGS(norm));
464  }
465  }
466 
467  if (normals) {
468  for (i = 0; i < num_faces; i++) {
469  fprintf(fp, "f %d//%d %d//%d %d//%d\n", faces[3*i]+v_offset, i+1, faces[3*i+1]+v_offset, i+1, faces[3*i+2]+v_offset, i+1);
470  }
471  } else {
472  for (i = 0; i < num_faces; i++) {
473  fprintf(fp, "f %d %d %d\n", faces[3*i]+v_offset, faces[3*i+1]+v_offset, faces[3*i+2]+v_offset);
474  }
475  }
476 
477  v_offset += num_vertices;
478 }
479 
480 
481 static void
482 stl_write_bot(struct rt_bot_internal *bot, FILE *fp, char *name)
483 {
484  fastf_t *vertices;
485  int num_faces, *faces;
486  point_t A;
487  point_t B;
488  point_t C;
489  vect_t BmA;
490  vect_t CmA;
491  vect_t norm;
492  int i, vi;
493 
494  vertices = bot->vertices;
495  num_faces = bot->num_faces;
496  faces = bot->faces;
497 
498  fprintf(fp, "solid %s\n", name);
499  for (i = 0; i < num_faces; i++) {
500  vi = 3*faces[3*i];
501  VSET(A, vertices[vi], vertices[vi+1], vertices[vi+2]);
502  vi = 3*faces[3*i+1];
503  VSET(B, vertices[vi], vertices[vi+1], vertices[vi+2]);
504  vi = 3*faces[3*i+2];
505  VSET(C, vertices[vi], vertices[vi+1], vertices[vi+2]);
506 
507  VSUB2(BmA, B, A);
508  VSUB2(CmA, C, A);
509  if (bot->orientation != RT_BOT_CW) {
510  VCROSS(norm, BmA, CmA);
511  } else {
512  VCROSS(norm, CmA, BmA);
513  }
514  VUNITIZE(norm);
515 
516  fprintf(fp, " facet normal %f %f %f\n", V3ARGS(norm));
517  fprintf(fp, " outer loop\n");
518  fprintf(fp, " vertex %f %f %f\n", V3ARGS_SCALE(A));
519  fprintf(fp, " vertex %f %f %f\n", V3ARGS_SCALE(B));
520  fprintf(fp, " vertex %f %f %f\n", V3ARGS_SCALE(C));
521  fprintf(fp, " endloop\n");
522  fprintf(fp, " endfacet\n");
523  }
524  fprintf(fp, "endsolid %s\n", name);
525 }
526 
527 
528 static void
529 stl_write_bot_binary(struct rt_bot_internal *bot, int fd, char *UNUSED(name))
530 {
531  fastf_t *vertices;
532  size_t num_faces;
533  int *faces;
534  point_t A;
535  point_t B;
536  point_t C;
537  vect_t BmA;
538  vect_t CmA;
539  vect_t norm;
540  unsigned long i, j, vi;
541 
542  vertices = bot->vertices;
543  num_faces = bot->num_faces;
544  faces = bot->faces;
545 
546  /* Write out the vertex data for each triangle */
547  for (i = 0; (size_t)i < num_faces; i++) {
548  float flts[12];
549  float *flt_ptr;
550  unsigned char vert_buffer[50];
551  int ret;
552 
553  vi = 3*faces[3*i];
554  VSET(A, vertices[vi], vertices[vi+1], vertices[vi+2]);
555  vi = 3*faces[3*i+1];
556  VSET(B, vertices[vi], vertices[vi+1], vertices[vi+2]);
557  vi = 3*faces[3*i+2];
558  VSET(C, vertices[vi], vertices[vi+1], vertices[vi+2]);
559 
560  VSUB2(BmA, B, A);
561  VSUB2(CmA, C, A);
562  if (bot->orientation != RT_BOT_CW) {
563  VCROSS(norm, BmA, CmA);
564  } else {
565  VCROSS(norm, CmA, BmA);
566  }
567  VUNITIZE(norm);
568 
569  VSCALE(A, A, cfactor);
570  VSCALE(B, B, cfactor);
571  VSCALE(C, C, cfactor);
572 
573  memset(vert_buffer, 0, sizeof(vert_buffer));
574 
575  flt_ptr = flts;
576  VMOVE(flt_ptr, norm);
577  flt_ptr += 3;
578  VMOVE(flt_ptr, A);
579  flt_ptr += 3;
580  VMOVE(flt_ptr, B);
581  flt_ptr += 3;
582  VMOVE(flt_ptr, C);
583  flt_ptr += 3;
584 
585  bu_cv_htonf(vert_buffer, (const unsigned char *)flts, 12);
586  for (j = 0; j < 12; j++) {
587  lswap((unsigned int *)&vert_buffer[j*4]);
588  }
589  ret = write(fd, vert_buffer, 50);
590  if (ret < 0) {
591  perror("write");
592  }
593  }
594 }
595 
596 
597 void
598 _ged_bot_dump(struct directory *dp, struct rt_bot_internal *bot, FILE *fp, int fd, const char *file_ext, const char *db_name)
599 {
600  int ret;
601 
602  if (output_directory) {
603  char *cp;
604  struct bu_vls file_name = BU_VLS_INIT_ZERO;
605 
606  bu_vls_strcpy(&file_name, output_directory);
607  bu_vls_putc(&file_name, '/');
608  cp = dp->d_namep;
609  while (*cp != '\0') {
610  if (*cp == '/') {
611  bu_vls_putc(&file_name, '@');
612  } else if (*cp == '.' || isspace((int)*cp)) {
613  bu_vls_putc(&file_name, '_');
614  } else {
615  bu_vls_putc(&file_name, *cp);
616  }
617  cp++;
618  }
619  bu_vls_strcat(&file_name, file_ext);
620 
621  if (binary && output_type == OTYPE_STL) {
622  char buf[81]; /* need exactly 80 chars for header */
623  unsigned char tot_buffer[4];
624 
625  if ((fd=open(bu_vls_addr(&file_name), O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
626  perror(bu_vls_addr(&file_name));
627  bu_log("Cannot open binary output file (%s) for writing\n", bu_vls_addr(&file_name));
628  bu_vls_free(&file_name);
629  return;
630  }
631 
632  /* Write out STL header */
633  memset(buf, 0, sizeof(buf));
634  bu_strlcpy(buf, "BRL-CAD generated STL FILE", sizeof(buf));
635  ret = write(fd, &buf, 80);
636  if (ret < 0) {
637  perror("write");
638  }
639 
640  /* write a place keeper for the number of triangles */
641  memset(buf, 0, 4);
642  ret = write(fd, &buf, 4);
643  if (ret < 0) {
644  perror("write");
645  }
646 
647  stl_write_bot_binary(bot, fd, dp->d_namep);
648 
649  /* Re-position pointer to 80th byte */
650  lseek(fd, 80, SEEK_SET);
651 
652  /* Write out number of triangles */
653  *(uint32_t *)tot_buffer = htonl((unsigned long)total_faces);
654  lswap((unsigned int *)tot_buffer);
655  ret = write(fd, tot_buffer, 4);
656  if (ret < 0) {
657  perror("write");
658  }
659 
660  close(fd);
661  } else {
662  if ((fp=fopen(bu_vls_addr(&file_name), "wb+")) == NULL) {
663  perror(bu_vls_addr(&file_name));
664  bu_log("Cannot open ASCII output file (%s) for writing\n", bu_vls_addr(&file_name));
665  bu_vls_free(&file_name);
666  return;
667  }
668 
669  switch (output_type) {
670  case OTYPE_DXF:
671  fprintf(fp,
672  "0\nSECTION\n2\nHEADER\n999\n%s (BOT from %s)\n0\nENDSEC\n0\nSECTION\n2\nENTITIES\n",
673  dp->d_namep, db_name);
674  dxf_write_bot(bot, fp, dp->d_namep);
675  fprintf(fp, "0\nENDSEC\n0\nEOF\n");
676  break;
677  case OTYPE_OBJ:
678  v_offset = 1;
679  fprintf(fp, "mtllib %s\n", bu_vls_addr(&obj_materials_file));
680  obj_write_bot(bot, fp, dp->d_namep);
681  break;
682  case OTYPE_SAT:
683  curr_line_num = 0;
684 
685  sat_write_header(fp);
686 
687  sat_write_bot(bot, fp, dp->d_namep);
688  fprintf(fp, "End-of-ACIS-data\n");
689  break;
690  case OTYPE_STL:
691  default:
692  stl_write_bot(bot, fp, dp->d_namep);
693  break;
694  }
695 
696  fclose(fp);
697  }
698 
699  bu_vls_free(&file_name);
700  } else {
701  if (binary && output_type == OTYPE_STL) {
702  total_faces += bot->num_faces;
703  stl_write_bot_binary(bot, fd, dp->d_namep);
704  } else if (binary && output_type != OTYPE_STL) {
705  bu_log("Unsupported binary file type - only STL is currently supported\n");
706  return;
707  } else {
708  /* If we get to this point, we need fp - check for it */
709  if (fp) {
710  switch (output_type) {
711  case OTYPE_DXF:
712  dxf_write_bot(bot, fp, dp->d_namep);
713  break;
714  case OTYPE_OBJ:
715  obj_write_bot(bot, fp, dp->d_namep);
716  break;
717  case OTYPE_SAT:
718  sat_write_bot(bot, fp, dp->d_namep);
719  break;
720  case OTYPE_STL:
721  default:
722  stl_write_bot(bot, fp, dp->d_namep);
723  break;
724  }
725  } else {
726  bu_log("_ged_bot_dump: non-binay file requested but fp is NULL!\n");
727  }
728  }
729  }
730 }
731 
732 
733 static union tree *
734 bot_dump_leaf(struct db_tree_state *tsp,
735  const struct db_full_path *pathp,
736  struct rt_db_internal *ip,
737  void *client_data)
738 {
739  int ret;
740  union tree *curtree;
741  mat_t mat;
742  struct directory *dp;
743  struct rt_db_internal intern;
744  struct rt_bot_internal *bot;
745  struct _ged_bot_dump_client_data *gbdcdp = (struct _ged_bot_dump_client_data *)client_data;
746 
747  if (ip) RT_CK_DB_INTERNAL(ip);
748 
749  /* Indicate success by returning something other than TREE_NULL */
750  RT_GET_TREE(curtree, tsp->ts_resp);
751  curtree->tr_op = OP_NOP;
752 
753  dp = pathp->fp_names[pathp->fp_len-1];
754 
755  /* we only dump BOT primitives, so skip some obvious exceptions */
756  if (dp->d_major_type != DB5_MAJORTYPE_BRLCAD || dp->d_flags & RT_DIR_COMB)
757  return curtree;
758 
759  MAT_IDN(mat);
760 
761  /* get the internal form */
762  ret=rt_db_get_internal(&intern, dp, gbdcdp->gedp->ged_wdbp->dbip, mat, &rt_uniresource);
763 
764  if (ret < 0) {
765  bu_log("ged_bot_leaf: rt_get_internal failure %d on %s\n", ret, dp->d_namep);
766  return curtree;
767  }
768 
769  if (ret != ID_BOT) {
770  bu_log("ged_bot_leaf: %s is not a bot (ignored)\n", dp->d_namep);
771  rt_db_free_internal(&intern);
772  return curtree;
773  }
774 
775  bot = (struct rt_bot_internal *)intern.idb_ptr;
776  _ged_bot_dump(dp, bot, gbdcdp->fp, gbdcdp->fd, gbdcdp->file_ext, gbdcdp->gedp->ged_wdbp->dbip->dbi_filename);
777  rt_db_free_internal(&intern);
778 
779  return curtree;
780 }
781 
782 
783 static int
784 bot_dump_get_args(struct ged *gedp, int argc, const char *argv[])
785 {
786  int c;
787 
788  output_type = OTYPE_STL;
789  binary = 0;
790  normals = 0;
791  cfactor = 1.0;
792  output_file = NULL;
793  output_directory = NULL;
794  total_faces = 0;
795  v_offset = 1;
796  curr_line_num = 0;
797  bu_optind = 1;
798 
799  /* Get command line options. */
800  while ((c = bu_getopt(argc, (char * const *)argv, "bno:m:t:u:")) != -1) {
801  switch (c) {
802  case 'b': /* Binary output file */
803  binary=1;
804  break;
805  case 'n': /* Binary output file */
806  normals=1;
807  break;
808  case 'm':
809  output_directory = bu_optarg;
810  break;
811  case 'o': /* Output file name. */
812  output_file = bu_optarg;
813  break;
814  case 't':
815  if (BU_STR_EQUAL("dxf", bu_optarg))
816  output_type = OTYPE_DXF;
817  else if (BU_STR_EQUAL("obj", bu_optarg))
818  output_type = OTYPE_OBJ;
819  else if (BU_STR_EQUAL("sat", bu_optarg))
820  output_type = OTYPE_SAT;
821  else if (BU_STR_EQUAL("stl", bu_optarg))
822  output_type = OTYPE_STL;
823  else {
824  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
825  return GED_ERROR;
826  }
827  break;
828  case 'u':
829  cfactor = bu_units_conversion(bu_optarg);
830  if (ZERO(cfactor))
831  cfactor = 1.0;
832  else
833  cfactor = 1.0 / cfactor;
834 
835  break;
836  default:
837  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
838  return GED_ERROR;
839  }
840  }
841 
842  return GED_OK;
843 }
844 
845 
846 int
847 ged_bot_dump(struct ged *gedp, int argc, const char *argv[])
848 {
849  int ret;
850  struct rt_db_internal intern;
851  struct rt_bot_internal *bot;
852  struct directory *dp;
853  char *file_ext = NULL;
854  FILE *fp = (FILE *)0;
855  int fd = -1;
856  mat_t mat;
857  int i;
858  const char *cmd_name;
859 
861  GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
862 
863  /* initialize result */
864  bu_vls_trunc(gedp->ged_result_str, 0);
865 
866  /* must be wanting help */
867  if (argc == 1) {
868  bu_vls_printf(gedp->ged_result_str, usage, argv[0]);
869  return GED_HELP;
870  }
871 
872  using_dbot_dump = 0;
873 
874  if (bot_dump_get_args(gedp, argc, argv) == GED_ERROR)
875  return GED_ERROR;
876 
877  if (bu_optind > argc) {
878  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
879  return GED_ERROR;
880  }
881 
882  if (output_file && output_directory) {
883  fprintf(stderr, "ERROR: options \"-o\" and \"-m\" are mutually exclusive\n");
884  return GED_ERROR;
885  }
886 
887  if (!output_file && !output_directory) {
888  if (binary) {
889  bu_vls_printf(gedp->ged_result_str, "Can't output binary to stdout\nUsage: %s %s", argv[0], usage);
890  return GED_ERROR;
891  }
892  fp = stdout;
893 
894  /* Set this to something non-null in order to possibly write eof */
895  output_file = "stdout";
896  }
897 
898  if (output_file) {
899  if (binary && output_type == OTYPE_STL) {
900  char buf[81]; /* need exactly 80 chars for header */
901 
902  /* Open binary output file */
903  if ((fd=open(output_file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
904  perror(argv[0]);
905  bu_vls_printf(gedp->ged_result_str, "Cannot open binary output file (%s) for writing\n", output_file);
906  return GED_ERROR;
907  }
908 
909  /* Write out STL header if output file is binary */
910  memset(buf, 0, sizeof(buf));
911  bu_strlcpy(buf, "BRL-CAD generated STL FILE", sizeof(buf));
912  ret = write(fd, &buf, 80);
913  if (ret < 0) {
914  perror("write");
915  }
916 
917  /* write a place keeper for the number of triangles */
918  memset(buf, 0, 4);
919  ret = write(fd, &buf, 4);
920  if (ret < 0) {
921  perror("write");
922  }
923  } else {
924  /* Open ASCII output file */
925  if ((fp=fopen(output_file, "wb+")) == NULL) {
926  perror(argv[0]);
927  bu_vls_printf(gedp->ged_result_str, "Cannot open ascii output file (%s) for writing\n", output_file);
928  return GED_ERROR;
929  }
930 
931  switch (output_type) {
932  case OTYPE_DXF:
933  /* output DXF header and start of TABLES section */
934  fprintf(fp,
935  "0\nSECTION\n2\nHEADER\n999\n%s (All Bots)\n0\nENDSEC\n0\nSECTION\n2\nENTITIES\n",
936  argv[argc-1]);
937  break;
938  case OTYPE_SAT:
939  sat_write_header(fp);
940  break;
941  default:
942  break;
943  }
944  }
945  }
946 
947  /* save the command name */
948  cmd_name = argv[0];
949 
950  /* skip past the command name and optional args */
951  argc -= bu_optind;
952  argv += bu_optind;
953 
954  if (output_directory) {
955  switch (output_type) {
956  case OTYPE_DXF:
957  file_ext = ".dxf";
958  break;
959  case OTYPE_OBJ:
960  file_ext = ".obj";
961  break;
962  case OTYPE_SAT:
963  file_ext = ".sat";
964  break;
965  case OTYPE_STL:
966  default:
967  file_ext = ".stl";
968  break;
969  }
970  }
971 
972  MAT_IDN(mat);
973 
974  if (argc < 1) {
975  /* dump all the bots */
977 
978  /* we only dump BOT primitives, so skip some obvious exceptions */
979  if (dp->d_major_type != DB5_MAJORTYPE_BRLCAD) continue;
980  if (dp->d_flags & RT_DIR_COMB) continue;
981 
982  /* get the internal form */
983  i = rt_db_get_internal(&intern, dp, gedp->ged_wdbp->dbip, mat, &rt_uniresource);
984  if (i < 0) {
985  fprintf(stderr, "%s: rt_get_internal failure %d on %s\n", cmd_name, i, dp->d_namep);
986  continue;
987  }
988 
989  if (i != ID_BOT) {
990  continue;
991  }
992 
993  bot = (struct rt_bot_internal *)intern.idb_ptr;
994  _ged_bot_dump(dp, bot, fp, fd, file_ext, gedp->ged_wdbp->dbip->dbi_filename);
995  rt_db_free_internal(&intern);
996 
998  } else {
999  int ac = 1;
1000  int ncpu = 1;
1001  char *av[2];
1002  struct _ged_bot_dump_client_data gbdcdp = {NULL, NULL, 0, NULL};
1003 
1004  av[1] = (char *)0;
1005  gbdcdp.gedp = gedp;
1006  gbdcdp.fp = fp;
1007  gbdcdp.fd = fd;
1008  gbdcdp.file_ext = file_ext;
1009 
1010  for (i = 0; i < argc; ++i) {
1011  av[0] = (char *)argv[i];
1012  ret = db_walk_tree(gedp->ged_wdbp->dbip,
1013  ac,
1014  (const char **)av,
1015  ncpu,
1017  0,
1018  0,
1019  bot_dump_leaf,
1020  (void *)&gbdcdp);
1021  }
1022  }
1023 
1024 
1025  if (output_file) {
1026  if (binary && output_type == OTYPE_STL) {
1027  unsigned char tot_buffer[4];
1028 
1029  /* Re-position pointer to 80th byte */
1030  lseek(fd, 80, SEEK_SET);
1031 
1032  /* Write out number of triangles */
1033  *(uint32_t *)tot_buffer = htonl((unsigned long)total_faces);
1034  lswap((unsigned int *)tot_buffer);
1035  ret = write(fd, tot_buffer, 4);
1036  if (ret < 0) {
1037  perror("write");
1038  }
1039 
1040  close(fd);
1041  } else {
1042  /* end of layers section, start of ENTITIES SECTION */
1043  switch (output_type) {
1044  case OTYPE_DXF:
1045  fprintf(fp, "0\nENDSEC\n0\nEOF\n");
1046  break;
1047  case OTYPE_SAT:
1048  fprintf(fp, "End-of-ACIS-data\n");
1049  break;
1050  default:
1051  break;
1052  }
1053 
1054  fclose(fp);
1055  }
1056  }
1057 
1058  return GED_OK;
1059 }
1060 
1061 
1062 static void
1063 write_data_arrows(struct bview_data_arrow_state *gdasp, FILE *fp, int sflag)
1064 {
1065  register int i;
1066 
1067  if (gdasp->gdas_draw) {
1068  struct _ged_obj_material *gomp;
1069 
1070  gomp = obj_get_material(gdasp->gdas_color[0],
1071  gdasp->gdas_color[1],
1072  gdasp->gdas_color[2],
1073  1);
1074  fprintf(fp, "usemtl %s\n", bu_vls_addr(&gomp->name));
1075 
1076  if (sflag)
1077  fprintf(fp, "g sdata_arrows\n");
1078  else
1079  fprintf(fp, "g data_arrows\n");
1080 
1081  for (i = 0; i < gdasp->gdas_num_points; i += 2) {
1082  point_t A, B;
1083  point_t BmA;
1084  point_t offset;
1085  point_t perp1, perp2;
1086  point_t a_base;
1087  point_t a_pt1, a_pt2, a_pt3, a_pt4;
1088 
1089  VMOVE(A, gdasp->gdas_points[i]);
1090  VMOVE(B, gdasp->gdas_points[i+1]);
1091 
1092  VSUB2(BmA, B, A);
1093 
1094  VUNITIZE(BmA);
1095  VSCALE(offset, BmA, -gdasp->gdas_tip_length);
1096 
1097  bn_vec_perp(perp1, BmA);
1098  VUNITIZE(perp1);
1099 
1100  VCROSS(perp2, BmA, perp1);
1101  VUNITIZE(perp2);
1102 
1103  VSCALE(perp1, perp1, gdasp->gdas_tip_width);
1104  VSCALE(perp2, perp2, gdasp->gdas_tip_width);
1105 
1106  VADD2(a_base, B, offset);
1107  VADD2(a_pt1, a_base, perp1);
1108  VADD2(a_pt2, a_base, perp2);
1109  VSUB2(a_pt3, a_base, perp1);
1110  VSUB2(a_pt4, a_base, perp2);
1111 
1112  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(A));
1113  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(B));
1114  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(a_pt1));
1115  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(a_pt2));
1116  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(a_pt3));
1117  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(a_pt4));
1118  }
1119 
1120  for (i = 0; i < gdasp->gdas_num_points; i += 2) {
1121  fprintf(fp, "l %d %d\n", (i/2*6)+v_offset, (i/2*6)+v_offset+1);
1122  fprintf(fp, "l %d %d\n", (i/2*6)+v_offset+1, (i/2*6)+v_offset+2);
1123  fprintf(fp, "l %d %d\n", (i/2*6)+v_offset+1, (i/2*6)+v_offset+3);
1124  fprintf(fp, "l %d %d\n", (i/2*6)+v_offset+1, (i/2*6)+v_offset+4);
1125  fprintf(fp, "l %d %d\n", (i/2*6)+v_offset+1, (i/2*6)+v_offset+5);
1126  fprintf(fp, "l %d %d\n", (i/2*6)+v_offset+2, (i/2*6)+v_offset+3);
1127  fprintf(fp, "l %d %d\n", (i/2*6)+v_offset+3, (i/2*6)+v_offset+4);
1128  fprintf(fp, "l %d %d\n", (i/2*6)+v_offset+4, (i/2*6)+v_offset+5);
1129  fprintf(fp, "l %d %d\n", (i/2*6)+v_offset+5, (i/2*6)+v_offset+2);
1130  }
1131 
1132  v_offset += ((gdasp->gdas_num_points/2)*6);
1133  }
1134 }
1135 
1136 
1137 static void
1138 write_data_axes(struct bview_data_axes_state *bndasp, FILE *fp, int sflag)
1139 {
1140  register int i;
1141 
1142  if (bndasp->draw) {
1143  fastf_t halfAxesSize;
1144  struct _ged_obj_material *gomp;
1145 
1146  halfAxesSize = bndasp->size * 0.5;
1147 
1148  gomp = obj_get_material(bndasp->color[0],
1149  bndasp->color[1],
1150  bndasp->color[2],
1151  1);
1152  fprintf(fp, "usemtl %s\n", bu_vls_addr(&gomp->name));
1153 
1154  if (sflag)
1155  fprintf(fp, "g sdata_axes\n");
1156  else
1157  fprintf(fp, "g data_axes\n");
1158 
1159  for (i = 0; i < bndasp->num_points; ++i) {
1160  point_t A, B;
1161 
1162  /* draw X axis with x/y offsets */
1163  VSET(A,
1164  bndasp->points[i][X] - halfAxesSize,
1165  bndasp->points[i][Y],
1166  bndasp->points[i][Z]);
1167  VSET(B,
1168  bndasp->points[i][X] + halfAxesSize,
1169  bndasp->points[i][Y],
1170  bndasp->points[i][Z]);
1171 
1172  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(A));
1173  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(B));
1174 
1175  /* draw Y axis with x/y offsets */
1176  VSET(A,
1177  bndasp->points[i][X],
1178  bndasp->points[i][Y] - halfAxesSize,
1179  bndasp->points[i][Z]);
1180  VSET(B,
1181  bndasp->points[i][X],
1182  bndasp->points[i][Y] + halfAxesSize,
1183  bndasp->points[i][Z]);
1184 
1185  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(A));
1186  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(B));
1187 
1188  /* draw Z axis with x/y offsets */
1189  VSET(A,
1190  bndasp->points[i][X],
1191  bndasp->points[i][Y],
1192  bndasp->points[i][Z] - halfAxesSize);
1193  VSET(B,
1194  bndasp->points[i][X],
1195  bndasp->points[i][Y],
1196  bndasp->points[i][Z] + halfAxesSize);
1197 
1198  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(A));
1199  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(B));
1200  }
1201 
1202  for (i = 0; i < bndasp->num_points; ++i) {
1203  fprintf(fp, "l %d %d\n", (i*6)+v_offset, (i*6)+v_offset+1);
1204  fprintf(fp, "l %d %d\n", (i*6)+v_offset+2, (i*6)+v_offset+3);
1205  fprintf(fp, "l %d %d\n", (i*6)+v_offset+4, (i*6)+v_offset+5);
1206  }
1207 
1208 
1209  v_offset += (bndasp->num_points*6);
1210  }
1211 }
1212 
1213 
1214 static void
1215 write_data_lines(struct bview_data_line_state *gdlsp, FILE *fp, int sflag)
1216 {
1217  register int i;
1218 
1219  if (gdlsp->gdls_draw) {
1220  struct _ged_obj_material *gomp;
1221 
1222  gomp = obj_get_material(gdlsp->gdls_color[0],
1223  gdlsp->gdls_color[1],
1224  gdlsp->gdls_color[2],
1225  1);
1226  fprintf(fp, "usemtl %s\n", bu_vls_addr(&gomp->name));
1227 
1228  if (sflag)
1229  fprintf(fp, "g sdata_lines\n");
1230  else
1231  fprintf(fp, "g data_lines\n");
1232 
1233  for (i = 0; i < gdlsp->gdls_num_points; i += 2) {
1234  point_t A, B;
1235 
1236  VMOVE(A, gdlsp->gdls_points[i]);
1237  VMOVE(B, gdlsp->gdls_points[i+1]);
1238 
1239  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(A));
1240  fprintf(fp, "v %f %f %f\n", V3ARGS_SCALE(B));
1241  }
1242 
1243  for (i = 0; i < gdlsp->gdls_num_points; i += 2) {
1244  fprintf(fp, "l %d %d\n", i+v_offset, i+v_offset+1);
1245  }
1246 
1247  v_offset += gdlsp->gdls_num_points;
1248  }
1249 }
1250 
1251 
1252 static void
1253 obj_write_data(struct ged *gedp, FILE *fp)
1254 {
1255  write_data_arrows(&gedp->ged_gvp->gv_data_arrows, fp, 0);
1256  write_data_arrows(&gedp->ged_gvp->gv_sdata_arrows, fp, 1);
1257 
1258  write_data_axes(&gedp->ged_gvp->gv_data_axes, fp, 0);
1259  write_data_axes(&gedp->ged_gvp->gv_sdata_axes, fp, 1);
1260 
1261  write_data_lines(&gedp->ged_gvp->gv_data_lines, fp, 0);
1262  write_data_lines(&gedp->ged_gvp->gv_sdata_lines, fp, 1);
1263 }
1264 
1265 
1266 static int
1267 data_dump(struct ged *gedp, FILE *fp)
1268 {
1269  switch (output_type) {
1270  case OTYPE_DXF:
1271  break;
1272  case OTYPE_OBJ:
1273  if (output_directory) {
1274  char *cp;
1275  struct bu_vls filepath = BU_VLS_INIT_ZERO;
1276  FILE *data_fp;
1277 
1278  cp = strrchr(output_directory, '/');
1279  if (!cp)
1280  cp = (char *)output_directory;
1281  else
1282  ++cp;
1283 
1284  if (*cp == '\0') {
1285  bu_vls_printf(gedp->ged_result_str, "data_dump: bad dirname - %s\n", output_directory);
1286  return GED_ERROR;
1287  }
1288 
1289  bu_vls_printf(&filepath, "%s/%s_data.obj", output_directory, cp);
1290 
1291  if ((data_fp=fopen(bu_vls_addr(&filepath), "wb+")) == NULL) {
1292  bu_vls_printf(gedp->ged_result_str, "data_dump: failed to open %s\n", bu_vls_addr(&filepath));
1293  bu_vls_free(&filepath);
1294  return GED_ERROR;
1295  }
1296 
1297  bu_vls_free(&filepath);
1298  obj_write_data(gedp, data_fp);
1299  fclose(data_fp);
1300  } else
1301  if (fp) {
1302  obj_write_data(gedp, fp);
1303  } else {
1304  bu_vls_printf(gedp->ged_result_str, "data_dump: bad FILE fp\n");
1305  return GED_ERROR;
1306  }
1307  break;
1308  case OTYPE_SAT:
1309  break;
1310  case OTYPE_STL:
1311  default:
1312  break;
1313  }
1314 
1315  return GED_OK;
1316 }
1317 
1318 
1319 int
1320 ged_dbot_dump(struct ged *gedp, int argc, const char *argv[])
1321 {
1322  int ret;
1323  char *file_ext = NULL;
1324  FILE *fp = (FILE *)0;
1325  int fd = -1;
1326  const char *cmd_name;
1327 
1330  GED_CHECK_VIEW(gedp, GED_ERROR);
1331  GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
1332 
1333  /* initialize result */
1334  bu_vls_trunc(gedp->ged_result_str, 0);
1335 
1336  /* must be wanting help */
1337  if (argc == 1) {
1338  bu_vls_printf(gedp->ged_result_str, usage, argv[0]);
1339  return GED_HELP;
1340  }
1341 
1342  using_dbot_dump = 1;
1343 
1344  if (bot_dump_get_args(gedp, argc, argv) == GED_ERROR)
1345  return GED_ERROR;
1346 
1347  if (bu_optind != argc) {
1348  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
1349  return GED_ERROR;
1350  }
1351 
1352  if (output_file && output_directory) {
1353  fprintf(stderr, "ERROR: options \"-o\" and \"-m\" are mutually exclusive\n");
1354  return GED_ERROR;
1355  }
1356 
1357  if (!output_file && !output_directory) {
1358  if (binary) {
1359  bu_vls_printf(gedp->ged_result_str, "Can't output binary to stdout\nUsage: %s %s", argv[0], usage);
1360  return GED_ERROR;
1361  }
1362  fp = stdout;
1363 
1364  /* Set this to something non-null in order to possibly write eof */
1365  output_file = "stdout";
1366  }
1367 
1368  if (output_file) {
1369  if (binary && output_type == OTYPE_STL) {
1370  char buf[81]; /* need exactly 80 chars for header */
1371 
1372  /* Open binary output file */
1373  if ((fd=open(output_file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
1374  perror(argv[0]);
1375  bu_vls_printf(gedp->ged_result_str, "Cannot open binary output file (%s) for writing\n", output_file);
1376  return GED_ERROR;
1377  }
1378 
1379  /* Write out STL header if output file is binary */
1380  memset(buf, 0, sizeof(buf));
1381  bu_strlcpy(buf, "BRL-CAD generated STL FILE", sizeof(buf));
1382  ret = write(fd, &buf, 80);
1383  if (ret < 0) {
1384  perror("write");
1385  }
1386 
1387  /* write a place keeper for the number of triangles */
1388  memset(buf, 0, 4);
1389  ret = write(fd, &buf, 4);
1390  if (ret < 0) {
1391  perror("write");
1392  }
1393  } else {
1394  /* Open ASCII output file */
1395  if ((fp=fopen(output_file, "wb+")) == NULL) {
1396  perror(argv[0]);
1397  bu_vls_printf(gedp->ged_result_str, "Cannot open ascii output file (%s) for writing\n", output_file);
1398  return GED_ERROR;
1399  }
1400 
1401  switch (output_type) {
1402  case OTYPE_DXF:
1403  /* output DXF header and start of TABLES section */
1404  fprintf(fp,
1405  "0\nSECTION\n2\nHEADER\n999\n%s (All Bots)\n0\nENDSEC\n0\nSECTION\n2\nENTITIES\n",
1406  argv[argc-1]);
1407  break;
1408  case OTYPE_SAT:
1409  sat_write_header(fp);
1410  break;
1411  default:
1412  break;
1413  }
1414  }
1415  }
1416 
1417  /* save the command name */
1418  cmd_name = argv[0];
1419 
1420  if (output_directory) {
1421  switch (output_type) {
1422  case OTYPE_DXF:
1423  file_ext = ".dxf";
1424  break;
1425  case OTYPE_OBJ:
1426  file_ext = ".obj";
1427 
1428  BU_LIST_INIT(&HeadObjMaterials);
1429 
1430  {
1431  char *cp;
1432  struct bu_vls filepath = BU_VLS_INIT_ZERO;
1433 
1434  cp = strrchr(output_directory, '/');
1435  if (!cp)
1436  cp = (char *)output_directory;
1437  else
1438  ++cp;
1439 
1440  if (*cp == '\0') {
1441  bu_vls_printf(gedp->ged_result_str, "%s: bad dirname - %s\n", cmd_name, output_directory);
1442  return GED_ERROR;
1443  }
1444 
1445  bu_vls_trunc(&obj_materials_file, 0);
1446  bu_vls_printf(&obj_materials_file, "%s.mtl", cp);
1447 
1448  bu_vls_printf(&filepath, "%s/%s", output_directory, bu_vls_addr(&obj_materials_file));
1449 
1450  if ((obj_materials_fp=fopen(bu_vls_addr(&filepath), "wb+")) == NULL) {
1451  bu_vls_printf(gedp->ged_result_str, "%s: failed to open %s\n", cmd_name, bu_vls_addr(&filepath));
1452  bu_vls_free(&obj_materials_file);
1453  bu_vls_free(&filepath);
1454  return GED_ERROR;
1455  }
1456 
1457  bu_vls_free(&filepath);
1458  }
1459 
1460  num_obj_materials = 0;
1461 
1462  break;
1463  case OTYPE_SAT:
1464  file_ext = ".sat";
1465  break;
1466  case OTYPE_STL:
1467  default:
1468  file_ext = ".stl";
1469  break;
1470  }
1471  } else if (output_type == OTYPE_OBJ) {
1472  char *cp;
1473 
1474  bu_vls_trunc(&obj_materials_file, 0);
1475 
1476  cp = strrchr(output_file, '.');
1477  if (!cp)
1478  bu_vls_printf(&obj_materials_file, "%s.mtl", output_file);
1479  else {
1480  /* ignore everything after the last '.' */
1481  *cp = '\0';
1482  bu_vls_printf(&obj_materials_file, "%s.mtl", output_file);
1483  *cp = '.';
1484  }
1485 
1486  BU_LIST_INIT(&HeadObjMaterials);
1487 
1488  if ((obj_materials_fp=fopen(bu_vls_addr(&obj_materials_file), "wb+")) == NULL) {
1489  bu_vls_printf(gedp->ged_result_str, "%s: failed to open %s\n", cmd_name, bu_vls_addr(&obj_materials_file));
1490  bu_vls_free(&obj_materials_file);
1491  fclose(fp);
1492  return GED_ERROR;
1493  }
1494 
1495  num_obj_materials = 0;
1496 
1497  fprintf(fp, "mtllib %s\n", bu_vls_addr(&obj_materials_file));
1498  }
1499 
1500  dl_botdump(gedp->ged_gdp->gd_headDisplay, gedp->ged_wdbp->dbip, fp, fd, file_ext, output_type, &curr_obj_red, &curr_obj_green, &curr_obj_blue, &curr_obj_alpha);
1501 
1502  data_dump(gedp, fp);
1503 
1504  if (output_file) {
1505  if (binary && output_type == OTYPE_STL) {
1506  unsigned char tot_buffer[4];
1507 
1508  /* Re-position pointer to 80th byte */
1509  lseek(fd, 80, SEEK_SET);
1510 
1511  /* Write out number of triangles */
1512  *(uint32_t *)tot_buffer = htonl((unsigned long)total_faces);
1513  lswap((unsigned int *)tot_buffer);
1514  ret = write(fd, tot_buffer, 4);
1515  if (ret < 0) {
1516  perror("write");
1517  }
1518 
1519  close(fd);
1520  } else {
1521  /* end of layers section, start of ENTITIES SECTION */
1522  switch (output_type) {
1523  case OTYPE_DXF:
1524  fprintf(fp, "0\nENDSEC\n0\nEOF\n");
1525  break;
1526  case OTYPE_SAT:
1527  fprintf(fp, "End-of-ACIS-data\n");
1528  break;
1529  default:
1530  break;
1531  }
1532 
1533  fclose(fp);
1534  }
1535  }
1536 
1537  if (output_type == OTYPE_OBJ) {
1538  bu_vls_free(&obj_materials_file);
1539  obj_free_materials();
1540  fclose(obj_materials_fp);
1541  }
1542 
1543  return GED_OK;
1544 }
1545 
1546 
1547 /*
1548  * Local Variables:
1549  * tab-width: 8
1550  * mode: C
1551  * indent-tabs-mode: t
1552  * c-file-style: "stroustrup"
1553  * End:
1554  * ex: shiftwidth=4 tabstop=8
1555  */
void bu_vls_init(struct bu_vls *vp)
Definition: vls.c:56
#define GED_OK
Definition: ged.h:55
FILE * obj_materials_fp
Definition: bot_dump.c:83
char * d_namep
pointer to name string
Definition: raytrace.h:859
#define BU_LIST_FOR(p, structure, hp)
Definition: list.h:365
#define FOR_ALL_DIRECTORY_START(_dp, _dbip)
Definition: raytrace.h:895
unsigned char d_major_type
object major type
Definition: raytrace.h:870
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
int rt_db_get_internal(struct rt_db_internal *ip, const struct directory *dp, const struct db_i *dbip, const mat_t mat, struct resource *resp)
Definition: dir.c:76
fastf_t C[2 *MAX_CNT+1][2 *MAX_CNT+1]
Definition: dsp_brep.cpp:38
Definition: list.h:118
int ged_bot_dump(struct ged *gedp, int argc, const char *argv[])
Definition: bot_dump.c:847
size_t fp_len
Definition: db_fullpath.h:44
struct bview_data_axes_state gv_sdata_axes
Definition: bview.h:245
#define OP_NOP
Leaf with no effect.
Definition: raytrace.h:1132
Definition: ged.h:338
struct db_i * dbip
Definition: raytrace.h:1266
Definition: clone.c:90
void bu_vls_strcat(struct bu_vls *vp, const char *s)
Definition: vls.c:368
#define VSET(a, b, c, d)
Definition: color.c:53
int curr_obj_green
Definition: bot_dump.c:86
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
#define ID_BOT
Bag o' triangles.
Definition: raytrace.h:488
#define GED_CHECK_ARGC_GT_0(_gedp, _argc, _flags)
Definition: ged.h:202
#define BU_LIST_INIT_ZERO
Definition: list.h:167
unsigned char g
Definition: bot_dump.c:74
#define FOR_ALL_DIRECTORY_END
Definition: raytrace.h:899
struct rt_wdb * ged_wdbp
Definition: ged.h:340
char * bu_optarg
Definition: globals.c:91
Header file for the BRL-CAD common definitions.
int bu_optind
Definition: globals.c:89
long time(time_t *)
#define BU_LIST_APPEND(old, new)
Definition: list.h:197
void dl_botdump(struct bu_list *hdlp, struct db_i *dbip, FILE *fp, int fd, char *file_ext, int output_type, int *red, int *green, int *blue, fastf_t *alpha)
struct bview_data_line_state gv_sdata_lines
Definition: bview.h:247
int bu_getopt(int nargc, char *const nargv[], const char *ostr)
Definition: getopt.c:43
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
struct bview_data_axes_state gv_data_axes
Definition: bview.h:240
#define SEEK_SET
Definition: db_open.c:52
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
Definition: color.c:49
void * memset(void *s, int c, size_t n)
struct resource rt_uniresource
default. Defined in librt/globals.c
Definition: globals.c:41
#define GED_CHECK_VIEW(_gedp, _flags)
Definition: ged.h:140
unsigned char b
Definition: bot_dump.c:75
#define GED_CHECK_DATABASE_OPEN(_gedp, _flags)
Definition: ged.h:114
#define RT_CK_DB_INTERNAL(_p)
Definition: raytrace.h:207
double bu_units_conversion(const char *str)
Definition: units.c:234
point_t * points
Definition: bview.h:103
struct bu_vls obj_materials_file
Definition: bot_dump.c:82
void _ged_bot_dump(struct directory *dp, struct rt_bot_internal *bot, FILE *fp, int fd, const char *file_ext, const char *db_name)
Definition: bot_dump.c:598
#define bu_strlcpy(dst, src, size)
Definition: str.h:60
#define V3ARGS(a)
Definition: color.c:56
void lswap(unsigned int *v)
Definition: stl_read.c:402
struct bu_list HeadObjMaterials
Definition: bot_dump.c:81
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
point_t * gdls_points
Definition: bview.h:159
#define GED_CHECK_DRAWABLE(_gedp, _flags)
Definition: ged.h:129
#define UNUSED(parameter)
Definition: common.h:239
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
struct directory ** fp_names
array of dir pointers
Definition: db_fullpath.h:46
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
struct bu_vls * ged_result_str
Definition: ged.h:357
struct resource * ts_resp
Per-CPU data.
Definition: raytrace.h:1074
#define BU_LIST_WHILE(p, structure, hp)
Definition: list.h:410
struct ged_drawable * ged_gdp
Definition: ged.h:360
struct bu_vls name
Definition: bot_dump.c:72
int curr_obj_blue
Definition: bot_dump.c:87
point_t * gdas_points
Definition: bview.h:142
int curr_obj_red
Definition: bot_dump.c:85
#define ZERO(val)
Definition: units.c:38
int ged_dbot_dump(struct ged *gedp, int argc, const char *argv[])
Definition: bot_dump.c:1320
#define BU_LIST_INIT(_hp)
Definition: list.h:148
void * idb_ptr
Definition: raytrace.h:195
#define RT_DIR_COMB
combination
Definition: raytrace.h:884
struct db_tree_state wdb_initial_tree_state
Definition: raytrace.h:1267
struct bview_data_arrow_state gv_sdata_arrows
Definition: bview.h:244
#define RT_GET_TREE(_tp, _res)
Definition: raytrace.h:1210
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
#define V3ARGS_SCALE(_a)
Definition: bot_dump.c:56
#define GED_HELP
Definition: ged.h:62
struct bview_data_arrow_state gv_data_arrows
Definition: bview.h:239
#define A
Definition: msr.c:51
void bu_cv_htonf(unsigned char *out, const unsigned char *in, size_t count)
Definition: color.c:51
void bu_vls_strcpy(struct bu_vls *vp, const char *s)
Definition: vls.c:310
void bn_vec_perp(vect_t new_vec, const vect_t old_vec)
Definition: mat.c:616
struct bview_data_line_state gv_data_lines
Definition: bview.h:242
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
int db_walk_tree(struct db_i *dbip, int argc, const char **argv, int ncpu, const struct db_tree_state *init_state, int(*reg_start_func)(struct db_tree_state *, const struct db_full_path *, const struct rt_comb_internal *, void *client_data), union tree *(*reg_end_func)(struct db_tree_state *, const struct db_full_path *, union tree *, void *client_data), union tree *(*leaf_func)(struct db_tree_state *, const struct db_full_path *, struct rt_db_internal *, void *client_data), void *client_data)
#define BU_LIST_DEQUEUE(cur)
Definition: list.h:209
unsigned char r
Definition: bot_dump.c:73
int d_flags
flags
Definition: raytrace.h:869
Definition: vls.h:56
fastf_t curr_obj_alpha
Definition: bot_dump.c:88
char * dbi_filename
file name
Definition: raytrace.h:805
double fastf_t
Definition: defines.h:300
otype
Definition: ged_private.h:214
void bu_vls_putc(struct bu_vls *vp, int c)
Definition: vls.c:666
int num_obj_materials
Definition: bot_dump.c:84
struct bu_list l
Definition: bot_dump.c:71
void rt_db_free_internal(struct rt_db_internal *ip)
Definition: dir.c:216
Definition: color.c:50
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126