BRL-CAD
analyze.c
Go to the documentation of this file.
1 /* A N A L Y Z E . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1985-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This program 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 program 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/analyze.c
21  *
22  * The analyze command.
23  *
24  */
25 
26 #include "common.h"
27 
28 #include <math.h>
29 #include <string.h>
30 #include <assert.h>
31 
32 
33 
34 #include "vmath.h"
35 #include "bn.h"
36 #include "rt/arb_edit.h"
37 #include "raytrace.h"
38 #include "rtgeom.h"
39 
40 #include "./ged_private.h"
41 
42 /**
43  * TODO: primitives that still need implementing
44  * ehy
45  * metaball
46  * nmg
47  * rhc
48  */
49 
50 /* Conversion factor for Gallons to cubic millimeters */
51 #define GALLONS_TO_MM3 3785411.784
52 
53 
54 /* ARB face printout array */
55 static const int prface[5][6] = {
56  {123, 124, 234, 134, -111, -111}, /* ARB4 */
57  {1234, 125, 235, 345, 145, -111}, /* ARB5 */
58  {1234, 2365, 1564, 512, 634, -111}, /* ARB6 */
59  {1234, 567, 145, 2376, 1265, 4375}, /* ARB7 */
60  {1234, 5678, 1584, 2376, 1265, 4378}, /* ARB8 */
61 };
62 
63 
64 /* edge definition array */
65 static const int nedge[5][24] = {
66  {0, 1, 1, 2, 2, 0, 0, 3, 3, 2, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* ARB4 */
67  {0, 1, 1, 2, 2, 3, 0, 3, 0, 4, 1, 4, 2, 4, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1}, /* ARB5 */
68  {0, 1, 1, 2, 2, 3, 0, 3, 0, 4, 1, 4, 2, 5, 3, 5, 4, 5, -1, -1, -1, -1, -1, -1}, /* ARB6 */
69  {0, 1, 1, 2, 2, 3, 0, 3, 0, 4, 3, 4, 1, 5, 2, 6, 4, 5, 5, 6, 4, 6, -1, -1}, /* ARB7 */
70  {0, 1, 1, 2, 2, 3, 0, 3, 0, 4, 4, 5, 1, 5, 5, 6, 6, 7, 4, 7, 3, 7, 2, 6}, /* ARB8 */
71 };
72 
73 
74 /* contains information used to analyze a polygonal face */
75 struct poly_face
76 {
77  char label[5];
78  size_t npts;
79  point_t *pts;
80  plane_t plane_eqn;
81  fastf_t area;
82 };
83 
84 
85 #define POLY_FACE_INIT_ZERO { { 0, 0, 0, 0, 0 }, 0, NULL, HINIT_ZERO, 0.0 }
86 
87 #define ADD_PT(face, pt) do { VMOVE((face).pts[(face).npts], (pt)); (face).npts++; } while (0)
88 
89 /* structures and subroutines for analyze pretty printing */
90 
91 #define FBUFSIZ 100
92 #define NFIELDS 9
93 #define NOT_A_PLANE -1
94 typedef struct row_field
95 {
96  int nchars;
97  char buf[FBUFSIZ];
98 } field_t;
99 
100 typedef struct table_row
101 {
102  int nfields;
104 } row_t;
105 
106 typedef struct table
107 {
108  int nrows;
110 } table_t;
111 
112 void get_dashes(field_t *f, const int ndashes)
113 {
114  int i;
115  f->buf[0] = '\0';
116  for (i = 0; i < ndashes; ++i) {
117  bu_strlcat(f->buf, "-", FBUFSIZ);
118  }
119  f->nchars = ndashes;
120 }
121 
122 
123 void print_volume_table(struct ged *gedp
124  , const fastf_t tot_vol
125  , const fastf_t tot_area
126  , const fastf_t tot_gallons
127  )
128 {
129 
130 /* table format
131 
132  +------------------------------------+
133  | Volume = 7999999999.99999905 |
134  | Surface Area = 24000000.00000000 |
135  | Gallons = 2113.37641887 |
136  +------------------------------------+
137 
138 */
139  /* track actual table column widths */
140  /* this table has 1 column (plus a name column) */
141  int maxwidth[2] = {0, 0};
142  field_t dashes;
143  char* fnames[3] = {"Volume",
144  "Surface Area",
145  "Gallons"};
146  int indent = 4; /* number spaces to indent the table */
147  int table_width_chars;
148  table_t table;
149  int i, nd, field;
150 
151  table.nrows = 3;
152  table.rows = (row_t *)bu_calloc(3, sizeof(row_t), "print_volume_table: rows");
153  for (i = 0; i < table.nrows; ++i) {
154  fastf_t val = 0.0;
155 
156  /* field 0 */
157  field = 0;
158  table.rows[i].fields[0].nchars = snprintf(table.rows[i].fields[field].buf, FBUFSIZ, "%s",
159  fnames[i]);
160  if (maxwidth[field] < table.rows[i].fields[field].nchars)
161  maxwidth[field] = table.rows[i].fields[field].nchars;
162 
163  if (i == 0) {
164  val = tot_vol;
165  } else if (i == 1) {
166  val = tot_area;
167  } else if (i == 2) {
168  val = tot_gallons;
169  }
170 
171  /* field 1 */
172  field = 1;
173  if (val < 0) {
174  table.rows[i].fields[1].nchars = snprintf(table.rows[i].fields[field].buf, FBUFSIZ, "COULD NOT DETERMINE");
175  } else {
176  table.rows[i].fields[1].nchars = snprintf(table.rows[i].fields[field].buf, FBUFSIZ, "%10.8f", val);
177  }
178  if (maxwidth[field] < table.rows[i].fields[field].nchars)
179  maxwidth[field] = table.rows[i].fields[field].nchars;
180  }
181 
182  /* get total table width */
183  table_width_chars = maxwidth[0] + maxwidth[1];
184  table_width_chars += 2 + 2; /* 2 chars at each end of a row */
185  table_width_chars += 3; /* ' = ' between the two fields of a row */
186 
187  /* newline following previous table */
188  bu_vls_printf(gedp->ged_result_str, "\n");
189 
190  /* header row 1 */
191  nd = table_width_chars - 4;
192  get_dashes(&dashes, nd);
193  bu_vls_printf(gedp->ged_result_str, "%-*.*s+-%-*.*s-+\n",
194  indent, indent, " ",
195  nd, nd, dashes.buf);
196 
197  /* the three data rows */
198  for (i = 0; i < table.nrows; ++i) {
199  bu_vls_printf(gedp->ged_result_str, "%-*.*s| %-*.*s = %*.*s |\n",
200  indent, indent, " ",
201  maxwidth[0], maxwidth[0], table.rows[i].fields[0].buf,
202  maxwidth[1], maxwidth[1], table.rows[i].fields[1].buf);
203  }
204 
205  /* closing table row */
206  bu_vls_printf(gedp->ged_result_str, "%-*.*s+-%-*.*s-+\n",
207  indent, indent, " ",
208  nd, nd, dashes.buf);
209  bu_free((char *)table.rows, "print_volume_table: rows");
210 }
211 
212 
213 void print_edges_table(struct ged *gedp, table_t *table)
214 {
215 
216 /* table header
217 
218  +--------------------+--------------------+--------------------+--------------------+
219  | EDGE LEN | EDGE LEN | EDGE LEN | EDGE LEN |
220  +--------------------+--------------------+--------------------+--------------------+
221 
222 */
223 
224  int i;
225  int tcol, nd, nrow, nrows;
226  int maxwidth[] = {0, 0, 0,
227  0, 0, 0,
228  0, 0};
229  int indent = 2;
230  field_t dashes;
231  char EDGE[] = {"EDGE"};
232  int elen = strlen(EDGE);
233  char LEN[] = {"LENGTH"};
234  int llen = strlen(LEN);
235  char buf[FBUFSIZ];
236 
237  /* put four edges per row making 8 columns */
238  /* this table has 8 columns per row: 2 columns per edge; 4 edges per row */
239 
240  /* collect max table column widths */
241  tcol = 0;
242  for (i = 0; i < table->nrows; ++i) {
243  /* field 0 */
244  int field = 0;
245  if (maxwidth[tcol] < table->rows[i].fields[field].nchars)
246  maxwidth[tcol] = table->rows[i].fields[field].nchars;
247  if (maxwidth[tcol] < elen)
248  maxwidth[tcol] = elen;
249 
250  /* field 1 */
251  field = 1;
252  if (maxwidth[tcol+1] < table->rows[i].fields[field].nchars)
253  maxwidth[tcol+1] = table->rows[i].fields[field].nchars;
254  if (maxwidth[tcol] < llen)
255  maxwidth[tcol] = llen;
256 
257  /* iterate on columns */
258  tcol += 2;
259  tcol = tcol > 6 ? 0 : tcol;
260  }
261 
262  /* header row 1 */
263  /* print dashes in 4 sets */
264  nd = maxwidth[0] + maxwidth[1] + 3; /* 1 space between numbers and one at each end */
265  get_dashes(&dashes, nd);
266  bu_vls_printf(gedp->ged_result_str, "%-*.*s+%-*.*s",
267  indent, indent, " ",
268  nd, nd, dashes.buf);
269  nd = maxwidth[2] + maxwidth[3] + 3; /* 1 space between numbers and one at each end */
270  get_dashes(&dashes, nd);
271  bu_vls_printf(gedp->ged_result_str, "+%-*.*s",
272  nd, nd, dashes.buf);
273  nd = maxwidth[4] + maxwidth[5] + 3; /* 1 space between numbers and one at each end */
274  get_dashes(&dashes, nd);
275  bu_vls_printf(gedp->ged_result_str, "+%-*.*s",
276  nd, nd, dashes.buf);
277  nd = maxwidth[6] + maxwidth[7] + 3; /* 1 space between numbers and one at each end */
278  get_dashes(&dashes, nd);
279  bu_vls_printf(gedp->ged_result_str, "+%-*.*s+\n",
280  nd, nd, dashes.buf);
281 
282  /* header row 2 */
283  /* print titles in 4 sets */
284 
285  /* bu_vls_printf can't handle this at the moment */
286  bu_vls_printf(gedp->ged_result_str, "%-*.*s| %-*.*s %*.*s ",
287  indent, indent, " ",
288  maxwidth[0], maxwidth[0], EDGE,
289  maxwidth[1], maxwidth[1], LEN);
290  bu_vls_printf(gedp->ged_result_str, "| %-*.*s %*.*s ",
291  maxwidth[2], maxwidth[2], EDGE,
292  maxwidth[3], maxwidth[3], LEN);
293  bu_vls_printf(gedp->ged_result_str, "| %-*.*s %*.*s ",
294  maxwidth[4], maxwidth[4], EDGE,
295  maxwidth[5], maxwidth[5], LEN);
296  bu_vls_printf(gedp->ged_result_str, "| %-*.*s %*.*s |\n",
297  maxwidth[6], maxwidth[6], EDGE,
298  maxwidth[7], maxwidth[7], LEN);
299 
300  /* header row 3 */
301  /* print dashes in 4 sets */
302  nd = maxwidth[0] + maxwidth[1] + 3; /* 1 space between numbers and one at each end */
303  get_dashes(&dashes, nd);
304  bu_vls_printf(gedp->ged_result_str, "%-*.*s+%-*.*s",
305  indent, indent, " ",
306  nd, nd, dashes.buf);
307  nd = maxwidth[2] + maxwidth[3] + 3; /* 1 space between numbers and one at each end */
308  get_dashes(&dashes, nd);
309  bu_vls_printf(gedp->ged_result_str, "+%-*.*s",
310  nd, nd, dashes.buf);
311  nd = maxwidth[4] + maxwidth[5] + 3; /* 1 space between numbers and one at each end */
312  get_dashes(&dashes, nd);
313  bu_vls_printf(gedp->ged_result_str, "+%-*.*s",
314  nd, nd, dashes.buf);
315  nd = maxwidth[6] + maxwidth[7] + 3; /* 1 space between numbers and one at each end */
316  get_dashes(&dashes, nd);
317  bu_vls_printf(gedp->ged_result_str, "+%-*.*s+\n",
318  nd, nd, dashes.buf);
319 
320  /* print the data lines */
321  /* collect max table column widths */
322  tcol = 0;
323  nrow = 0;
324  for (i = 0; i < table->nrows; ++i) {
325  int field;
326 
327  if (tcol == 0) {
328  /* need to start a row */
329  snprintf(buf, FBUFSIZ, "%-*.*s|",
330  indent, indent, " ");
331  bu_vls_printf(gedp->ged_result_str, "%s", buf);
332  }
333 
334  /* data in sets of two */
335  /* field 0 */
336  field = 0;
337  /* FIXME: using snprintf because bu_vls_printf is broken for complex formats */
338  snprintf(buf, FBUFSIZ, " %-*.*s",
339  maxwidth[tcol], maxwidth[tcol], table->rows[i].fields[field].buf);
340  bu_vls_printf(gedp->ged_result_str, "%s", buf);
341 
342  /* field 1 */
343  field = 1;
344  /* FIXME: using snprintf because bu_vls_printf is broken for complex formats */
345  snprintf(buf, FBUFSIZ, " %-*.*s |",
346  maxwidth[tcol+1], maxwidth[tcol+1], table->rows[i].fields[field].buf);
347  bu_vls_printf(gedp->ged_result_str, "%s", buf);
348 
349  /* iterate on columns */
350  tcol += 2;
351 
352  if (tcol > 6) {
353  /* time for a newline to end the row */
354  bu_vls_printf(gedp->ged_result_str, "\n");
355  tcol = 0;
356  ++nrow;
357  }
358  }
359 
360  /* we may have a row to finish */
361  nrows = table->nrows % 4;
362  if (nrows) {
363  assert(tcol < 8);
364 
365  /* write blanks */
366  while (tcol < 7) {
367 
368  /* data in sets of two */
369  /* this is field 0 */
370  /* FIXME: using snprintf because bu_vls_printf is broken for complex formats */
371  snprintf(buf, FBUFSIZ, " %-*.*s",
372  maxwidth[tcol], maxwidth[tcol], " ");
373  bu_vls_printf(gedp->ged_result_str, "%s", buf);
374 
375  /* this is field 1 */
376  /* FIXME: using snprintf because bu_vls_printf is broken for complex formats */
377  snprintf(buf, FBUFSIZ, " %-*.*s |",
378  maxwidth[tcol+1], maxwidth[tcol+1], " ");
379  bu_vls_printf(gedp->ged_result_str, "%s", buf);
380 
381  /* iterate on columns */
382  tcol += 2;
383 
384  if (tcol > 6) {
385  /* time for a newline to end the row */
386  bu_vls_printf(gedp->ged_result_str, "\n");
387  }
388  }
389  }
390 
391  /* close the table */
392  /* print dashes in 4 sets */
393  nd = maxwidth[0] + maxwidth[1] + 3; /* 1 space between numbers and one at each end */
394  get_dashes(&dashes, nd);
395  bu_vls_printf(gedp->ged_result_str, "%-*.*s+%-*.*s",
396  indent, indent, " ",
397  nd, nd, dashes.buf);
398  nd = maxwidth[2] + maxwidth[3] + 3; /* 1 space between numbers and one at each end */
399  get_dashes(&dashes, nd);
400  bu_vls_printf(gedp->ged_result_str, "+%-*.*s",
401  nd, nd, dashes.buf);
402  nd = maxwidth[4] + maxwidth[5] + 3; /* 1 space between numbers and one at each end */
403  get_dashes(&dashes, nd);
404  bu_vls_printf(gedp->ged_result_str, "+%-*.*s",
405  nd, nd, dashes.buf);
406  nd = maxwidth[6] + maxwidth[7] + 3; /* 1 space between numbers and one at each end */
407  get_dashes(&dashes, nd);
408  bu_vls_printf(gedp->ged_result_str, "+%-*.*s+\n",
409  nd, nd, dashes.buf);
410 }
411 
412 
413 void print_faces_table(struct ged *gedp, table_t *table)
414 {
415 
416 /* table header
417 
418  +------+-----------------------------+--------------------------------------------------+-----------------+
419  | FACE | ROT FB | PLANE EQUATION | SURFACE AREA |
420  +------+-----------------------------+--------------------------------------------------+-----------------+
421 
422 */
423 
424  /* track actual table column widths */
425  /* this table has 8 columns */
426  int maxwidth[8] = {0, 0, 0,
427  0, 0, 0,
428  0, 0};
429  int i, j;
430  int c0, h1a, h1b, h1c;
431  int h2a, h2b, h2c;
432  int c2, c2a, c2b, c2c;
433  int f7, f7a, f7b, f7c;
434  int nd, tnd;
435  field_t dashes;
436  char ROT[] = {"ROT"};
437  char FB[] = {"FB"};
438  char PA[] = {"PLANE EQUATION"};
439  char SA[] = {"SURFACE AREA"};
440 
441  /* get max fields widths */
442  for (i = 0; i < table->nrows; ++i) {
443  for (j = 0; j < table->rows[i].nfields; ++j) {
444  if (table->rows[i].fields[j].nchars > maxwidth[j])
445  maxwidth[j] = table->rows[i].fields[j].nchars;
446  }
447  }
448 
449  /* blank line following previous table */
450  bu_vls_printf(gedp->ged_result_str, "\n");
451 
452  /* get max width of header columns (not counting single space on either side) */
453  c0 = maxwidth[0] > 4 ? maxwidth[0] : 4;
454 
455  /* print "ROT" in center of field 1 space */
456  h1b = strlen(ROT);
457  h1a = (maxwidth[1] - h1b)/2;
458  h1c = (maxwidth[1] - h1b - h1a);
459 
460  /* print "FB" in center of field 2 space */
461  h2b = strlen(FB);
462  h2a = (maxwidth[2] - h2b)/2;
463  h2c = (maxwidth[2] - h2b - h2a);
464 
465  /* get width of subcolumns of header column 2 */
466  /* print "PLANE EQUATION" in center of columns 2 space */
467  c2 = maxwidth[3] + maxwidth[4] + maxwidth[5] + maxwidth[6] + 3; /* 3 spaces between fields */
468  c2b = strlen(PA);
469  c2a = (c2 - c2b)/2;
470  c2c = (c2 - c2b - c2a);
471 
472  /* print "SURFACE AREA" in center of field 7 space */
473  f7b = strlen(SA);
474  f7 = maxwidth[7] > f7b ? maxwidth[7] : f7b;
475  f7a = (f7 - f7b)/2;
476  f7c = (f7 - f7b - f7a);
477 
478  /* print the pieces */
479 
480  /* header row 1 */
481  bu_vls_printf(gedp->ged_result_str, "+-");
482  nd = c0; tnd = nd;
483  get_dashes(&dashes, nd);
484  bu_vls_printf(gedp->ged_result_str, "%-*.*s",
485  nd, nd, dashes.buf);
486  bu_vls_printf(gedp->ged_result_str, "-+-");
487  nd = h1a + h1b + h1c + 1 + h2a + h2b + h2c; tnd += nd + 3;
488  get_dashes(&dashes, nd);
489  bu_vls_printf(gedp->ged_result_str, "%*.*s",
490  nd, nd, dashes.buf);
491  bu_vls_printf(gedp->ged_result_str, "-+-");
492  nd = c2a + c2b + c2c; tnd += nd + 3;
493  get_dashes(&dashes, nd);
494  bu_vls_printf(gedp->ged_result_str, "%*.*s",
495  nd, nd, dashes.buf);
496  bu_vls_printf(gedp->ged_result_str, "-+-");
497  nd = f7a + f7b + f7c; tnd += nd + 3;
498  get_dashes(&dashes, nd);
499  bu_vls_printf(gedp->ged_result_str, "%*.*s",
500  nd, nd, dashes.buf);
501  bu_vls_printf(gedp->ged_result_str, "-+\n");
502 
503  /* header row 2 */
504  bu_vls_printf(gedp->ged_result_str, "| ");
505 
506  bu_vls_printf(gedp->ged_result_str, "%-*.*s", c0, c0, "FACE");
507 
508  bu_vls_printf(gedp->ged_result_str, " | ");
509 
510 
511  bu_vls_printf(gedp->ged_result_str, "%*.*s", h1a, h1a, " ");
512 
513  bu_vls_printf(gedp->ged_result_str, "%*.*s", h1b, h1b, ROT);
514 
515  bu_vls_printf(gedp->ged_result_str, "%*.*s", h1c+h2a, h1c+h2a, " ");
516 
517  bu_vls_printf(gedp->ged_result_str, "%*.*s", h2b, h2b, FB);
518 
519  bu_vls_printf(gedp->ged_result_str, "%*.*s ", h2c, h2c, " ");
520 
521 
522  bu_vls_printf(gedp->ged_result_str, " | ");
523 
524 
525  bu_vls_printf(gedp->ged_result_str, "%*.*s", c2a, c2a, " ");
526 
527  bu_vls_printf(gedp->ged_result_str, "%*.*s", c2b, c2b, PA);
528 
529  bu_vls_printf(gedp->ged_result_str, "%*.*s", c2c, c2c, " ");
530 
531 
532  bu_vls_printf(gedp->ged_result_str, " | ");
533 
534  bu_vls_printf(gedp->ged_result_str, "%*.*s", f7a, f7a, " ");
535 
536  bu_vls_printf(gedp->ged_result_str, "%*.*s", f7b, f7b, SA);
537 
538  bu_vls_printf(gedp->ged_result_str, "%*.*s", f7c, f7c, " ");
539 
540  bu_vls_printf(gedp->ged_result_str, " |\n");
541 
542  /* header row 3 */
543  bu_vls_printf(gedp->ged_result_str, "+-");
544  nd = c0; tnd = nd;
545  get_dashes(&dashes, nd);
546  bu_vls_printf(gedp->ged_result_str, "%-*.*s",
547  nd, nd, dashes.buf);
548  bu_vls_printf(gedp->ged_result_str, "-+-");
549  nd = h1a + h1b + h1c + 1 + h2a + h2b + h2c; tnd += nd + 3;
550  get_dashes(&dashes, nd);
551  bu_vls_printf(gedp->ged_result_str, "%*.*s",
552  nd, nd, dashes.buf);
553  bu_vls_printf(gedp->ged_result_str, "-+-");
554  nd = c2a + c2b + c2c; tnd += nd + 3;
555  get_dashes(&dashes, nd);
556  bu_vls_printf(gedp->ged_result_str, "%*.*s",
557  nd, nd, dashes.buf);
558  bu_vls_printf(gedp->ged_result_str, "-+-");
559  nd = f7a + f7b + f7c; tnd += nd + 3;
560  get_dashes(&dashes, nd);
561  bu_vls_printf(gedp->ged_result_str, "%*.*s",
562  nd, nd, dashes.buf);
563  bu_vls_printf(gedp->ged_result_str, "-+\n");
564 
565  /* output table data rows */
566  for (i = 0; i < table->nrows; ++i) {
567  /* may not have a row with data */
568  if (table->rows[i].nfields == 0)
569  continue;
570  if (table->rows[i].nfields == NOT_A_PLANE)
571  bu_vls_printf(gedp->ged_result_str, "***NOT A PLANE ***");
572 
573  bu_vls_printf(gedp->ged_result_str, "|");
574  for (j = 0; j < table->rows[i].nfields; ++j) {
575  assert(table->rows[i].fields[j].buf);
576  bu_vls_printf(gedp->ged_result_str, " %*.*s",
577  maxwidth[j], maxwidth[j],
578  table->rows[i].fields[j].buf);
579  /* do we need a separator? */
580  if (j == 0 || j == 2 || j == 6 || j == 7)
581  bu_vls_printf(gedp->ged_result_str, " |");
582  }
583  /* close the row */
584  bu_vls_printf(gedp->ged_result_str, "\n");
585  }
586 
587  /* close the table with the ender row */
588  bu_vls_printf(gedp->ged_result_str, "+-");
589  nd = c0; tnd = nd;
590  get_dashes(&dashes, nd);
591  bu_vls_printf(gedp->ged_result_str, "%-*.*s",
592  nd, nd, dashes.buf);
593  bu_vls_printf(gedp->ged_result_str, "-+-");
594  nd = h1a + h1b + h1c + 1 + h2a + h2b + h2c; tnd += nd + 3;
595  get_dashes(&dashes, nd);
596  bu_vls_printf(gedp->ged_result_str, "%*.*s",
597  nd, nd, dashes.buf);
598  bu_vls_printf(gedp->ged_result_str, "-+-");
599  nd = c2a + c2b + c2c; tnd += nd + 3;
600  get_dashes(&dashes, nd);
601  bu_vls_printf(gedp->ged_result_str, "%*.*s",
602  nd, nd, dashes.buf);
603  bu_vls_printf(gedp->ged_result_str, "-+-");
604  nd = f7a + f7b + f7c; tnd += nd + 3;
605  get_dashes(&dashes, nd);
606  bu_vls_printf(gedp->ged_result_str, "%*.*s",
607  nd, nd, dashes.buf);
608  bu_vls_printf(gedp->ged_result_str, "-+\n");
609 }
610 
611 
612 /**
613  * general analyze function for primitives that can be analyzed using volume
614  * and surface area functions from the rt_functab.
615  * Currently used for:
616  * - ell
617  * - tor
618  * - tgc
619  * - rpc
620  * - eto
621  * - epa
622  * - part
623  */
624 HIDDEN void
625 analyze_general(struct ged *gedp, const struct rt_db_internal *ip)
626 {
627  fastf_t vol, area;
628  point_t centroid;
629 
630  vol = area = -1.0;
631 
632  if (OBJ[ip->idb_minor_type].ft_volume) {
633  OBJ[ip->idb_minor_type].ft_volume(&vol, ip);
634  }
635  if (OBJ[ip->idb_minor_type].ft_surf_area) {
636  OBJ[ip->idb_minor_type].ft_surf_area(&area, ip);
637  }
638 
639  if (OBJ[ip->idb_minor_type].ft_centroid) {
640  OBJ[ip->idb_minor_type].ft_centroid(&centroid, ip);
641  bu_vls_printf(gedp->ged_result_str, "\n Centroid: (%g, %g, %g)\n",
642  centroid[X] * gedp->ged_wdbp->dbip->dbi_base2local,
643  centroid[Y] * gedp->ged_wdbp->dbip->dbi_base2local,
644  centroid[Z] * gedp->ged_wdbp->dbip->dbi_base2local);
645  }
646 
647  print_volume_table(gedp,
648  vol
649  * gedp->ged_wdbp->dbip->dbi_base2local
650  * gedp->ged_wdbp->dbip->dbi_base2local
651  * gedp->ged_wdbp->dbip->dbi_base2local,
652  area
653  * gedp->ged_wdbp->dbip->dbi_base2local
654  * gedp->ged_wdbp->dbip->dbi_base2local,
655  vol/GALLONS_TO_MM3
656  );
657 }
658 
659 
660 /**
661  * finds direction cosines and rotation, fallback angles of a unit vector
662  * angles = pointer to 5 fastf_t's to store angles
663  * unitv = pointer to the unit vector (previously computed)
664  */
665 HIDDEN void
666 findang(fastf_t *angles, fastf_t *unitv)
667 {
668  int i;
669  fastf_t f;
670 
671  /* convert direction cosines into axis angles */
672  for (i = X; i <= Z; i++) {
673  if (unitv[i] <= -1.0)
674  angles[i] = -90.0;
675  else if (unitv[i] >= 1.0)
676  angles[i] = 90.0;
677  else
678  angles[i] = acos(unitv[i]) * RAD2DEG;
679  }
680 
681  /* fallback angle */
682  if (unitv[Z] <= -1.0)
683  unitv[Z] = -1.0;
684  else if (unitv[Z] >= 1.0)
685  unitv[Z] = 1.0;
686  angles[4] = asin(unitv[Z]);
687 
688  /* rotation angle */
689  /* For the tolerance below, on an SGI 4D/70, cos(asin(1.0)) != 0.0
690  * with an epsilon of +/- 1.0e-17, so the tolerance below was
691  * substituted for the original +/- 1.0e-20.
692  */
693  if ((f = cos(angles[4])) > 1.0e-16 || f < -1.0e-16) {
694  f = unitv[X]/f;
695  if (f <= -1.0)
696  angles[3] = 180.0;
697  else if (f >= 1.0)
698  angles[3] = 0.0;
699  else
700  angles[3] = RAD2DEG * acos(f);
701  } else
702  angles[3] = 0.0;
703 
704  if (unitv[Y] < 0)
705  angles[3] = 360.0 - angles[3];
706 
707  angles[4] *= RAD2DEG;
708 }
709 
710 
711 /**
712  * general analyze function for polygonal faces.
713  * Currently used for:
714  * - arb8
715  * - arbn
716  * - ars
717  *
718  * returns:
719  * - area in face->area
720  * - print_faces_table() information in row
721  * - sorts vertices in face->pts into ccw order
722  */
723 HIDDEN void
724 analyze_poly_face(struct ged *gedp, struct poly_face *face, row_t *row)
725 {
726  fastf_t angles[5];
727 
728  findang(angles, face->plane_eqn);
729 
730  /* sort points */
731  bn_polygon_sort_ccw(face->npts, face->pts, face->plane_eqn);
732  bn_polygon_area(&face->area, face->npts, (const point_t *)face->pts);
733 
734  /* store face information for pretty printing */
735  row->nfields = 8;
736  row->fields[0].nchars = sprintf(row->fields[0].buf, "%4s", face->label);
737  row->fields[1].nchars = sprintf(row->fields[1].buf, "%10.8f", angles[3]);
738  row->fields[2].nchars = sprintf(row->fields[2].buf, "%10.8f", angles[4]);
739  row->fields[3].nchars = sprintf(row->fields[3].buf, "%10.8f", face->plane_eqn[X]);
740  row->fields[4].nchars = sprintf(row->fields[4].buf, "%10.8f", face->plane_eqn[Y]);
741  row->fields[5].nchars = sprintf(row->fields[5].buf, "%10.8f", face->plane_eqn[Z]);
742  row->fields[6].nchars = sprintf(row->fields[6].buf, "%10.8f",
743  face->plane_eqn[W]*gedp->ged_wdbp->dbip->dbi_base2local);
744  row->fields[7].nchars = sprintf(row->fields[7].buf, "%10.8f",
746 }
747 
748 
749 HIDDEN void
750 analyze_edge(struct ged *gedp, const int edge, const struct rt_arb_internal *arb,
751  const int type, row_t *row)
752 {
753  int a = nedge[type][edge*2];
754  int b = nedge[type][edge*2+1];
755 
756  if (b == -1) {
757  row->nfields = 0;
758  return;
759  }
760 
761  row->nfields = 2;
762  row->fields[0].nchars = sprintf(row->fields[0].buf, "%d%d", a + 1, b + 1);
763  row->fields[1].nchars = sprintf(row->fields[1].buf, "%10.8f",
764  DIST_PT_PT(arb->pt[a], arb->pt[b])*gedp->ged_wdbp->dbip->dbi_base2local);
765 }
766 
767 
768 HIDDEN void
769 analyze_arb8(struct ged *gedp, const struct rt_db_internal *ip)
770 {
771  int i, type;
772  int cgtype; /* COMGEOM arb type: # of vertices */
773  table_t table; /* holds table data from child functions */
774  fastf_t tot_vol = 0.0, tot_area = 0.0;
775  point_t center_pt = VINIT_ZERO;
776  struct poly_face face = POLY_FACE_INIT_ZERO;
777  struct rt_arb_internal earb;
778  struct rt_arb_internal *arb = (struct rt_arb_internal *)ip->idb_ptr;
779  const int arb_faces[5][24] = rt_arb_faces;
780  RT_ARB_CK_MAGIC(arb);
781 
782  /* find the specific arb type, in GIFT order. */
783  if ((cgtype = rt_arb_std_type(ip, &gedp->ged_wdbp->wdb_tol)) == 0) {
784  bu_vls_printf(gedp->ged_result_str, "analyze_arb: bad ARB\n");
785  return;
786  }
787 
788  type = cgtype - 4;
789 
790  /* to get formatting correct, we need to collect the actual string
791  * lengths for each field BEFORE we start printing a table (fields
792  * are allowed to overflow the stated printf field width) */
793 
794  /* TABLE 1 =========================================== */
795  /* analyze each face, use center point of arb for reference */
796  rt_arb_centroid(&center_pt, ip);
797 
798  /* allocate pts array, maximum 4 verts per arb8 face */
799  face.pts = (point_t *)bu_calloc(4, sizeof(point_t), "analyze_arb8: pts");
800  /* allocate table rows, 12 rows needed for arb8 edges */
801  table.rows = (row_t *)bu_calloc(12, sizeof(row_t), "analyze_arb8: rows");
802 
803  table.nrows = 0;
804  for (face.npts = 0, i = 0; i < 6; face.npts = 0, i++) {
805  int a, b, c, d; /* 4 indices to face vertices */
806 
807  a = arb_faces[type][i*4+0];
808  b = arb_faces[type][i*4+1];
809  c = arb_faces[type][i*4+2];
810  d = arb_faces[type][i*4+3];
811 
812  if (a == -1) {
813  table.rows[i].nfields = 0;
814  continue;
815  }
816 
817  /* find plane eqn for this face */
818  if (bn_mk_plane_3pts(face.plane_eqn, arb->pt[a], arb->pt[b], arb->pt[c], &gedp->ged_wdbp->wdb_tol) < 0) {
819  bu_vls_printf(gedp->ged_result_str, "| %d%d%d%d | ***NOT A PLANE*** |\n",
820  a+1, b+1, c+1, d+1);
821  /* this row has 1 special fields */
822  table.rows[i].nfields = NOT_A_PLANE;
823  continue;
824  }
825 
826  ADD_PT(face, arb->pt[a]);
827  ADD_PT(face, arb->pt[b]);
828  ADD_PT(face, arb->pt[c]);
829  ADD_PT(face, arb->pt[d]);
830 
831  /* The plane equations returned by bn_mk_plane_3pts above do
832  * not necessarily point outward. Use the reference center
833  * point for the arb and reverse direction for any errant planes.
834  * This corrects the output rotation, fallback angles so that
835  * they always give the outward pointing normal vector. */
836  if (DIST_PT_PLANE(center_pt, face.plane_eqn) > 0.0) {
837  HREVERSE(face.plane_eqn, face.plane_eqn);
838  }
839 
840  snprintf(face.label, sizeof(face.label), "%d", prface[type][i]);
841 
842  analyze_poly_face(gedp, &face, &(table.rows[i]));
843  tot_area += face.area;
844  table.nrows++;
845  }
846 
847  /* and print it */
848  print_faces_table(gedp, &table);
849 
850  /* TABLE 2 =========================================== */
851  /* analyze each edge */
852 
853  /* blank line following previous table */
854  bu_vls_printf(gedp->ged_result_str, "\n");
855 
856  /* set up the records for arb4's and arb6's */
857  earb = *arb; /* struct copy */
858  if (cgtype == 4) {
859  VMOVE(earb.pt[3], earb.pt[4]);
860  } else if (cgtype == 6) {
861  VMOVE(earb.pt[5], earb.pt[6]);
862  }
863 
864  table.nrows = 0;
865  for (i = 0; i < 12; i++) {
866  analyze_edge(gedp, i, &earb, type, &(table.rows[i]));
867  if (nedge[type][i*2] == -1) {
868  break;
869  }
870  table.nrows += 1;
871  }
872 
873  print_edges_table(gedp, &table);
874 
875  /* TABLE 3 =========================================== */
876  /* find the volume - break arb8 into 6 arb4s */
877 
878  if (OBJ[ID_ARB8].ft_volume)
879  OBJ[ID_ARB8].ft_volume(&tot_vol, ip);
880 
881  print_volume_table(gedp,
882  tot_vol
883  * gedp->ged_wdbp->dbip->dbi_base2local
884  * gedp->ged_wdbp->dbip->dbi_base2local
885  * gedp->ged_wdbp->dbip->dbi_base2local,
886  tot_area
887  * gedp->ged_wdbp->dbip->dbi_base2local
888  * gedp->ged_wdbp->dbip->dbi_base2local,
889  tot_vol/GALLONS_TO_MM3
890  );
891 
892  bu_free((char *)face.pts, "analyze_arb8: pts");
893  bu_free((char *)table.rows, "analyze_arb8: rows");
894 }
895 
896 
897 HIDDEN void
898 analyze_arbn(struct ged *gedp, const struct rt_db_internal *ip)
899 {
900  size_t i;
901  fastf_t tot_vol = 0.0, tot_area = 0.0;
902  table_t table;
903  struct poly_face *faces;
904  struct bu_vls tmpstr = BU_VLS_INIT_ZERO;
905  struct rt_arbn_internal *aip = (struct rt_arbn_internal *)ip->idb_ptr;
906  size_t *npts = (size_t *)bu_calloc(aip->neqn, sizeof(size_t), "analyze_arbn: npts");
907  point_t **tmp_pts = (point_t **)bu_calloc(aip->neqn, sizeof(point_t *), "analyze_arbn: tmp_pts");
908  plane_t *eqs= (plane_t *)bu_calloc(aip->neqn, sizeof(plane_t), "analyze_arbn: eqs");
909 
910  /* allocate array of face structs */
911  faces = (struct poly_face *)bu_calloc(aip->neqn, sizeof(struct poly_face), "analyze_arbn: faces");
912  for (i = 0; i < aip->neqn; i++) {
913  HMOVE(faces[i].plane_eqn, aip->eqn[i]);
914  VUNITIZE(faces[i].plane_eqn);
915  /* allocate array of pt structs, max number of verts per faces = (# of faces) - 1 */
916  faces[i].pts = (point_t *)bu_calloc(aip->neqn - 1, sizeof(point_t), "analyze_arbn: pts");
917  tmp_pts[i] = faces[i].pts;
918  HMOVE(eqs[i], faces[i].plane_eqn);
919  }
920  /* allocate table rows, 1 row per plane eqn */
921  table.rows = (row_t *)bu_calloc(aip->neqn, sizeof(row_t), "analyze_arbn: rows");
922  table.nrows = aip->neqn;
923 
924  bn_polygon_mk_pts_planes(npts, tmp_pts, aip->neqn, (const plane_t *)eqs);
925 
926  for (i = 0; i < aip->neqn; i++) {
927  vect_t tmp;
928  bu_vls_sprintf(&tmpstr, "%4zu", i);
929  snprintf(faces[i].label, sizeof(faces[i].label), "%s", bu_vls_addr(&tmpstr));
930 
931  faces[i].npts = npts[i];
932 
933  /* calculate surface area */
934  analyze_poly_face(gedp, &faces[i], &table.rows[i]);
935  tot_area += faces[i].area;
936 
937  /* calculate volume */
938  VSCALE(tmp, faces[i].plane_eqn, faces[i].area);
939  tot_vol += VDOT(faces[i].pts[0], tmp);
940  }
941  tot_vol /= 3.0;
942 
943  print_faces_table(gedp, &table);
944  print_volume_table(gedp,
945  tot_vol
946  * gedp->ged_wdbp->dbip->dbi_base2local
947  * gedp->ged_wdbp->dbip->dbi_base2local
948  * gedp->ged_wdbp->dbip->dbi_base2local,
949  tot_area
950  * gedp->ged_wdbp->dbip->dbi_base2local
951  * gedp->ged_wdbp->dbip->dbi_base2local,
952  tot_vol/GALLONS_TO_MM3
953  );
954 
955  for (i = 0; i < aip->neqn; i++) {
956  bu_free((char *)faces[i].pts, "analyze_arbn: pts");
957  }
958  bu_free((char *)faces, "analyze_arbn: faces");
959  bu_free((char *)table.rows, "analyze_arbn: rows");
960  bu_free((char *)tmp_pts, "analyze_arbn: tmp_pts");
961  bu_free((char *)npts, "analyze_arbn: npts");
962  bu_free((char *)eqs, "analyze_arbn: eqs");
963  bu_vls_free(&tmpstr);
964 }
965 
966 
967 #define ARS_PT(ii, jj) (&arip->curves[i+(ii)][(j+(jj))*ELEMENTS_PER_VECT])
968 
969 HIDDEN void
970 analyze_ars(struct ged *gedp, const struct rt_db_internal *ip)
971 {
972  size_t i, j, k;
973  size_t nfaces = 0;
974  fastf_t tot_area = 0.0, tot_vol = 0.0;
975  table_t table;
976  plane_t old_plane = HINIT_ZERO;
977  struct bu_vls tmpstr = BU_VLS_INIT_ZERO;
978  struct poly_face face = POLY_FACE_INIT_ZERO;
979  struct rt_ars_internal *arip = (struct rt_ars_internal *)ip->idb_ptr;
980  RT_ARS_CK_MAGIC(arip);
981 
982  /* allocate pts array, max 3 pts per triangular face */
983  face.pts = (point_t *)bu_calloc(3, sizeof(point_t), "analyze_ars: pts");
984  /* allocate table rows, probably overestimating the number of rows needed */
985  table.rows = (row_t *)bu_calloc((arip->ncurves - 1) * 2 * arip->pts_per_curve, sizeof(row_t), "analyze_ars: rows");
986 
987  k = arip->pts_per_curve - 2;
988  for (i = 0; i < arip->ncurves - 1; i++) {
989  int double_ended = k != 1 && VEQUAL(&arip->curves[i][ELEMENTS_PER_VECT], &arip->curves[i][k * ELEMENTS_PER_VECT]);
990 
991  for (j = 0; j < arip->pts_per_curve; j++) {
992  vect_t tmp;
993 
994  if (double_ended && i != 0 && (j == 0 || j == k || j == arip->pts_per_curve - 1)) continue;
995 
996  /* first triangular face, make sure it's not a duplicate */
997  if (bn_mk_plane_3pts(face.plane_eqn, ARS_PT(0, 0), ARS_PT(1, 1), ARS_PT(0, 1), &gedp->ged_wdbp->wdb_tol) == 0
998  && !HEQUAL(old_plane, face.plane_eqn)) {
999  HMOVE(old_plane, face.plane_eqn);
1000  ADD_PT(face, ARS_PT(0, 1));
1001  ADD_PT(face, ARS_PT(0, 0));
1002  ADD_PT(face, ARS_PT(1, 1));
1003 
1004  bu_vls_sprintf(&tmpstr, "%zu%zu", i, j);
1005  snprintf(face.label, sizeof(face.label), "%s", bu_vls_addr(&tmpstr));
1006 
1007  /* surface area */
1008  analyze_poly_face(gedp, &face, &(table.rows[nfaces]));
1009  tot_area += face.area;
1010 
1011  /* volume */
1012  VSCALE(tmp, face.plane_eqn, face.area);
1013  tot_vol += fabs(VDOT(face.pts[0], tmp));
1014 
1015  face.npts = 0;
1016  nfaces++;
1017  }
1018 
1019  /* second triangular face, make sure it's not a duplicate */
1020  if (bn_mk_plane_3pts(face.plane_eqn, ARS_PT(1, 0), ARS_PT(1, 1), ARS_PT(0, 0), &gedp->ged_wdbp->wdb_tol) == 0
1021  && !HEQUAL(old_plane, face.plane_eqn)) {
1022  HMOVE(old_plane, face.plane_eqn);
1023  ADD_PT(face, ARS_PT(1, 0));
1024  ADD_PT(face, ARS_PT(0, 0));
1025  ADD_PT(face, ARS_PT(1, 1));
1026 
1027  bu_vls_sprintf(&tmpstr, "%zu%zu", i, j);
1028  snprintf(face.label, sizeof(face.label), "%s", bu_vls_addr(&tmpstr));
1029 
1030  analyze_poly_face(gedp, &face, &table.rows[nfaces]);
1031  tot_area += face.area;
1032 
1033  VSCALE(tmp, face.plane_eqn, face.area);
1034  tot_vol += fabs(VDOT(face.pts[0], tmp));
1035 
1036  face.npts = 0;
1037  nfaces++;
1038  }
1039  }
1040  }
1041  tot_vol /= 3.0;
1042  table.nrows = nfaces;
1043 
1044  print_faces_table(gedp, &table);
1045  print_volume_table(gedp,
1046  tot_vol
1047  * gedp->ged_wdbp->dbip->dbi_base2local
1048  * gedp->ged_wdbp->dbip->dbi_base2local
1049  * gedp->ged_wdbp->dbip->dbi_base2local,
1050  tot_area
1051  * gedp->ged_wdbp->dbip->dbi_base2local
1052  * gedp->ged_wdbp->dbip->dbi_base2local,
1053  tot_vol/GALLONS_TO_MM3
1054  );
1055 
1056  bu_free((char *)face.pts, "analyze_ars: pts");
1057  bu_free((char *)table.rows, "analyze_ars: rows");
1058  bu_vls_free(&tmpstr);
1059 }
1060 
1061 
1062 #define PROLATE 1
1063 #define OBLATE 2
1064 
1065 HIDDEN void
1066 analyze_superell(struct ged *gedp, const struct rt_db_internal *ip)
1067 {
1068  struct rt_superell_internal *superell = (struct rt_superell_internal *)ip->idb_ptr;
1069  fastf_t ma, mb, mc;
1070  fastf_t ecc, major_mag, minor_mag;
1071  fastf_t vol, sur_area;
1072  int type;
1073 
1074  RT_SUPERELL_CK_MAGIC(superell);
1075 
1076  ma = MAGNITUDE(superell->a);
1077  mb = MAGNITUDE(superell->b);
1078  mc = MAGNITUDE(superell->c);
1079 
1080  type = 0;
1081 
1082  vol = 4.0 * M_PI * ma * mb * mc / 3.0;
1083 
1084  if (fabs(ma-mb) < .00001 && fabs(mb-mc) < .00001) {
1085  /* have a sphere */
1086  sur_area = 4.0 * M_PI * ma * ma;
1087  goto print_results;
1088  }
1089  if (fabs(ma-mb) < .00001) {
1090  /* A == B */
1091  if (mc > ma) {
1092  /* oblate spheroid */
1093  type = OBLATE;
1094  major_mag = mc;
1095  minor_mag = ma;
1096  } else {
1097  /* prolate spheroid */
1098  type = PROLATE;
1099  major_mag = ma;
1100  minor_mag = mc;
1101  }
1102  } else
1103  if (fabs(ma-mc) < .00001) {
1104  /* A == C */
1105  if (mb > ma) {
1106  /* oblate spheroid */
1107  type = OBLATE;
1108  major_mag = mb;
1109  minor_mag = ma;
1110  } else {
1111  /* prolate spheroid */
1112  type = PROLATE;
1113  major_mag = ma;
1114  minor_mag = mb;
1115  }
1116  } else
1117  if (fabs(mb-mc) < .00001) {
1118  /* B == C */
1119  if (ma > mb) {
1120  /* oblate spheroid */
1121  type = OBLATE;
1122  major_mag = ma;
1123  minor_mag = mb;
1124  } else {
1125  /* prolate spheroid */
1126  type = PROLATE;
1127  major_mag = mb;
1128  minor_mag = ma;
1129  }
1130  } else {
1131  bu_vls_printf(gedp->ged_result_str, " Cannot find surface area\n");
1132  return;
1133  }
1134  ecc = sqrt(major_mag*major_mag - minor_mag*minor_mag) / major_mag;
1135  if (type == PROLATE) {
1136  sur_area = M_2PI * minor_mag * minor_mag +
1137  (M_2PI * (major_mag*minor_mag/ecc) * asin(ecc));
1138  } else {
1139  /* type == OBLATE */
1140  sur_area = M_2PI * major_mag * major_mag +
1141  (M_PI * (minor_mag*minor_mag/ecc) * log((1.0+ecc)/(1.0-ecc)));
1142  }
1143 
1144 print_results:
1145  print_volume_table(gedp,
1146  vol
1147  * gedp->ged_wdbp->dbip->dbi_base2local
1148  * gedp->ged_wdbp->dbip->dbi_base2local
1149  * gedp->ged_wdbp->dbip->dbi_base2local,
1150  sur_area
1151  * gedp->ged_wdbp->dbip->dbi_base2local
1152  * gedp->ged_wdbp->dbip->dbi_base2local,
1153  vol/GALLONS_TO_MM3
1154  );
1155 }
1156 
1157 
1158 HIDDEN void
1159 analyze_sketch(struct ged *gedp, const struct rt_db_internal *ip)
1160 {
1161  fastf_t area = -1;
1162  point_t centroid;
1163 
1164  if (OBJ[ID_SKETCH].ft_surf_area)
1165  OBJ[ID_SKETCH].ft_surf_area(&area, ip);
1166 
1167  if (area > 0.0) {
1168  bu_vls_printf(gedp->ged_result_str, "\nTotal Area: %10.8f",
1169  area
1170  * gedp->ged_wdbp->dbip->dbi_local2base
1171  * gedp->ged_wdbp->dbip->dbi_local2base
1172  );
1173  }
1174 
1175  if (OBJ[ID_SKETCH].ft_centroid) {
1176  OBJ[ID_SKETCH].ft_centroid(&centroid, ip);
1177  bu_vls_printf(gedp->ged_result_str, "\n Centroid: (%g, %g, %g)\n",
1178  centroid[X] * gedp->ged_wdbp->dbip->dbi_base2local,
1179  centroid[Y] * gedp->ged_wdbp->dbip->dbi_base2local,
1180  centroid[Z] * gedp->ged_wdbp->dbip->dbi_base2local);
1181  }
1182 }
1183 
1184 
1185 /**
1186  * Analyze command - prints loads of info about a solid
1187  * Format: analyze [name]
1188  * if 'name' is missing use solid being edited
1189  */
1190 
1191 /* Analyze solid in internal form */
1192 HIDDEN void
1193 analyze_do(struct ged *gedp, const struct rt_db_internal *ip)
1194 {
1195  /* XXX Could give solid name, and current units, here */
1196 
1197  switch (ip->idb_type) {
1198 
1199  case ID_ARB8:
1200  analyze_arb8(gedp, ip);
1201  break;
1202 
1203  case ID_BOT:
1204  analyze_general(gedp, ip);
1205  break;
1206 
1207  case ID_ARBN:
1208  analyze_arbn(gedp, ip);
1209  break;
1210 
1211  case ID_ARS:
1212  analyze_ars(gedp, ip);
1213  break;
1214 
1215  case ID_TGC:
1216  analyze_general(gedp, ip);
1217  break;
1218 
1219  case ID_ELL:
1220  analyze_general(gedp, ip);
1221  break;
1222 
1223  case ID_TOR:
1224  analyze_general(gedp, ip);
1225  break;
1226 
1227  case ID_RPC:
1228  analyze_general(gedp, ip);
1229  break;
1230 
1231  case ID_ETO:
1232  analyze_general(gedp, ip);
1233  break;
1234 
1235  case ID_EPA:
1236  analyze_general(gedp, ip);
1237  break;
1238 
1239  case ID_PARTICLE:
1240  analyze_general(gedp, ip);
1241  break;
1242 
1243  case ID_SUPERELL:
1244  analyze_superell(gedp, ip);
1245  break;
1246 
1247  case ID_SKETCH:
1248  analyze_sketch(gedp, ip);
1249  break;
1250 
1251  case ID_HYP:
1252  analyze_general(gedp, ip);
1253  break;
1254 
1255  case ID_PIPE:
1256  analyze_general(gedp, ip);
1257  break;
1258 
1259  case ID_VOL:
1260  analyze_general(gedp, ip);
1261  break;
1262 
1263  case ID_EXTRUDE:
1264  analyze_general(gedp, ip);
1265  break;
1266 
1267  default:
1268  bu_vls_printf(gedp->ged_result_str, "\nanalyze: unable to process %s solid\n",
1269  OBJ[ip->idb_type].ft_name);
1270  break;
1271  }
1272 }
1273 
1274 
1275 int
1276 ged_analyze(struct ged *gedp, int argc, const char *argv[])
1277 {
1278  struct directory *ndp;
1279  int i;
1280  struct rt_db_internal intern;
1281  static const char *usage = "object(s)";
1282 
1284  GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
1285 
1286  /* initialize result */
1287  bu_vls_trunc(gedp->ged_result_str, 0);
1288 
1289  /* must be wanting help */
1290  if (argc == 1) {
1291  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
1292  return GED_HELP;
1293  }
1294 
1295  /* use the names that were input */
1296  for (i = 1; i < argc; i++) {
1297  if ((ndp = db_lookup(gedp->ged_wdbp->dbip, argv[i], LOOKUP_NOISY)) == RT_DIR_NULL)
1298  continue;
1299 
1301 
1302  _ged_do_list(gedp, ndp, 1);
1303  analyze_do(gedp, &intern);
1304  rt_db_free_internal(&intern);
1305  }
1306 
1307  return GED_OK;
1308 }
1309 
1310 
1311 /*
1312  * Local Variables:
1313  * mode: C
1314  * tab-width: 8
1315  * indent-tabs-mode: t
1316  * c-file-style: "stroustrup"
1317  * End:
1318  * ex: shiftwidth=4 tabstop=8
1319  */
Definition: db_flip.c:35
void usage(struct ged *gedp)
Definition: coil.c:315
#define GED_OK
Definition: ged.h:55
#define ID_ARS
ARS.
Definition: raytrace.h:463
int nfields
Definition: analyze.c:102
HIDDEN void analyze_ars(struct ged *gedp, const struct rt_db_internal *ip)
Definition: analyze.c:970
#define FBUFSIZ
Definition: analyze.c:91
#define ADD_PT(face, pt)
Definition: analyze.c:87
#define NFIELDS
Definition: analyze.c:92
HIDDEN void analyze_do(struct ged *gedp, const struct rt_db_internal *ip)
Definition: analyze.c:1193
#define ID_PIPE
Pipe (wire) solid.
Definition: raytrace.h:473
Definition: ged.h:338
const mat_t bn_mat_identity
Matrix and vector functionality.
Definition: mat.c:46
struct db_i * dbip
Definition: raytrace.h:1266
#define ID_ARB8
Generalized ARB. V + 7 vectors.
Definition: raytrace.h:462
void rt_arb_centroid(point_t *cent, const struct rt_db_internal *ip)
Definition: arb8.c:345
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 M_PI
Definition: fft.h:35
struct directory * db_lookup(const struct db_i *, const char *name, int noisy)
Definition: db_lookup.c:153
void(* ft_volume)(fastf_t *, const struct rt_db_internal *)
Definition: raytrace.h:2202
#define ID_PARTICLE
Particle system solid.
Definition: raytrace.h:474
struct table table_t
#define PROLATE
Definition: analyze.c:1062
struct rt_wdb * ged_wdbp
Definition: ged.h:340
Header file for the BRL-CAD common definitions.
row_t * rows
Definition: analyze.c:109
#define ID_TOR
Toroid.
Definition: raytrace.h:459
void print_volume_table(struct ged *gedp, const fastf_t tot_vol, const fastf_t tot_area, const fastf_t tot_gallons)
Definition: analyze.c:123
void print_edges_table(struct ged *gedp, table_t *table)
Definition: analyze.c:213
field_t fields[NFIELDS]
Definition: analyze.c:103
#define rt_arb_faces
Definition: arb_edit.h:65
#define GED_ERROR
Definition: ged.h:61
#define HIDDEN
Definition: common.h:86
#define ID_VOL
3-D Volume
Definition: raytrace.h:471
int ged_analyze(struct ged *gedp, int argc, const char *argv[])
Definition: analyze.c:1276
HIDDEN void analyze_edge(struct ged *gedp, const int edge, const struct rt_arb_internal *arb, const int type, row_t *row)
Definition: analyze.c:750
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
HIDDEN void analyze_arb8(struct ged *gedp, const struct rt_db_internal *ip)
Definition: analyze.c:769
Definition: color.c:49
int bn_polygon_mk_pts_planes(size_t *npts, point_t **pts, size_t neqs, const plane_t *eqs)
Calculate for an array of plane_eqs, which build a polyhedron, the point_t's for each face...
Definition: polygon.c:137
void get_dashes(field_t *f, const int ndashes)
Definition: analyze.c:112
char buf[FBUFSIZ]
Definition: analyze.c:97
struct resource rt_uniresource
default. Defined in librt/globals.c
Definition: globals.c:41
#define GED_CHECK_DATABASE_OPEN(_gedp, _flags)
Definition: ged.h:114
#define ID_HYP
Hyperboloid of one sheet.
Definition: raytrace.h:510
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
void(* ft_surf_area)(fastf_t *, const struct rt_db_internal *)
Definition: raytrace.h:2205
HIDDEN void findang(fastf_t *angles, fastf_t *unitv)
Definition: analyze.c:666
HIDDEN void analyze_sketch(struct ged *gedp, const struct rt_db_internal *ip)
Definition: analyze.c:1159
void bu_vls_sprintf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:707
Editing operations for arb primitives.
struct row_field field_t
#define POLY_FACE_INIT_ZERO
Definition: analyze.c:85
void print_faces_table(struct ged *gedp, table_t *table)
Definition: analyze.c:413
char ft_name[17]
Definition: raytrace.h:2043
point_t * pts
Definition: arbn.c:1285
int bn_polygon_area(fastf_t *area, size_t npts, const point_t *pts)
Functions for working with polygons.
Definition: polygon.c:28
#define NOT_A_PLANE
Definition: analyze.c:93
Definition: analyze.c:106
void _ged_do_list(struct ged *gedp, struct directory *dp, int verbose)
Definition: list.c:39
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
#define ARS_PT(ii, jj)
Definition: analyze.c:967
struct bu_vls * ged_result_str
Definition: ged.h:357
size_t npts
Definition: arbn.c:1284
double dbi_base2local
unit conversion factors
Definition: raytrace.h:808
#define ID_ARBN
ARB with N faces.
Definition: raytrace.h:472
HIDDEN void analyze_general(struct ged *gedp, const struct rt_db_internal *ip)
Definition: analyze.c:625
#define ID_EPA
Elliptical Paraboloid.
Definition: raytrace.h:477
char label[5]
Definition: arbn.c:1283
HIDDEN void analyze_arbn(struct ged *gedp, const struct rt_db_internal *ip)
Definition: analyze.c:898
void * idb_ptr
Definition: raytrace.h:195
plane_t plane_eqn
Definition: arbn.c:1286
struct bn_tol wdb_tol
Definition: raytrace.h:1269
const struct rt_functab OBJ[]
Definition: table.c:159
#define ID_SUPERELL
Superquadratic ellipsoid.
Definition: raytrace.h:507
HIDDEN void analyze_superell(struct ged *gedp, const struct rt_db_internal *ip)
Definition: analyze.c:1066
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
#define RT_DIR_NULL
Definition: raytrace.h:875
#define LOOKUP_NOISY
Definition: raytrace.h:892
ustring label
#define GED_HELP
Definition: ged.h:62
int nrows
Definition: analyze.c:108
#define OBLATE
Definition: analyze.c:1063
int idb_minor_type
ID_xxx.
Definition: raytrace.h:193
#define GED_DB_GET_INTERNAL(_gedp, _intern, _dp, _mat, _resource, _flags)
Definition: ged.h:233
Definition: color.c:51
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
int rt_arb_std_type(const struct rt_db_internal *ip, const struct bn_tol *tol)
Definition: arb8.c:317
double dbi_local2base
local2mm
Definition: raytrace.h:807
struct table_row row_t
#define ID_EXTRUDE
Solid of extrusion.
Definition: raytrace.h:485
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
#define ID_RPC
Right Parabolic Cylinder.
Definition: raytrace.h:475
#define GALLONS_TO_MM3
Definition: analyze.c:51
HIDDEN void analyze_poly_face(struct ged *gedp, struct poly_face *face, row_t *row)
Definition: analyze.c:724
#define ID_TGC
Generalized Truncated General Cone.
Definition: raytrace.h:460
Definition: vls.h:56
fastf_t area
Definition: arbn.c:1287
#define ID_ETO
Elliptical Torus.
Definition: raytrace.h:479
double fastf_t
Definition: defines.h:300
int bn_mk_plane_3pts(plane_t plane, const point_t a, const point_t b, const point_t c, const struct bn_tol *tol)
#define ID_ELL
Ellipsoid.
Definition: raytrace.h:461
#define ID_SKETCH
2D sketch
Definition: raytrace.h:484
void rt_db_free_internal(struct rt_db_internal *ip)
Definition: dir.c:216
int nchars
Definition: analyze.c:96
Definition: color.c:50
void(* ft_centroid)(point_t *, const struct rt_db_internal *)
Definition: raytrace.h:2208
#define bu_strlcat(dst, src, size)
Definition: str.h:50
int bn_polygon_sort_ccw(size_t npts, point_t *pts, plane_t cmp)
Sort an array of point_ts, building a convex polygon, counter-clockwise.
Definition: polygon.c:182