PageRenderTime 74ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/brlcad/branches/bottie/src/rt/reshoot.c

https://bitbucket.org/vrrm/brl-cad-copy-for-fast-history-browsing-in-git
C | 424 lines | 198 code | 62 blank | 164 comment | 24 complexity | bdf599cccdfdb26b645b069d76b4c626 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, LGPL-2.1, Apache-2.0, AGPL-3.0, LGPL-3.0, GPL-3.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, 0BSD, BSD-3-Clause
  1. /* S H O T L I N E S . C
  2. * BRL-CAD
  3. *
  4. * Copyright (c) 2004-2011 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 reshoot.c
  21. *
  22. * A program to shoot reshoot and compare results to previous runs.
  23. *
  24. * This program is geared towards performing regression tests of the
  25. * BRL-CAD libraries. A candidate application is run with
  26. * the RT_G_DEBUG flag DEBUG_ALLHITS set. This causes the application
  27. * to log all calls to the application hit() routine, and print the
  28. * contents of the struct partition. The log is processed to
  29. * eliminate extraneous information to produce the input to this
  30. * program. The following awk program, will suffice: @verbatim
  31. /Pnt/ { START=index($0, "(") + 1
  32. STR=substr($0, START, index($0, ")") - START)
  33. gsub( ", ", ",", STR)
  34. printf "Pnt=%s\n", STR
  35. }
  36. /Dir/ { START=index($0, "(") + 1
  37. STR=substr($0, START, index($0, ")") - START)
  38. gsub( ", ", ",", STR)
  39. printf "Dir=%s\n", STR
  40. }
  41. /PT/ { PARTIN=$3
  42. PARTOUT=$5
  43. }
  44. /InHIT/ { INHIT=$2 }
  45. /OutHIT/ { OUTHIT=$2 }
  46. /Region/ { printf "\tregion=%s in=%s in%s out=%s out%s\n", $2, PARTIN, INHIT, PARTOUT, OUTHIT}
  47. @endverbatim
  48. * If this awk program is stored in the file p.awk then: @verbatim
  49. awk -f p.awk < logfile > inputfile
  50. @endverbatim
  51. * will produce a suitable input file for this program. The form is as
  52. * follows: @verbatim
  53. Pnt=1, 2, 3
  54. Dir=4, 5, 6
  55. region=/all.g/platform.r in=platform.s indist=10016.8 out=platform.s outdist=10023.8
  56. @endverbatim
  57. * where the line begining with "region" may be repeated any number of times, representing each
  58. * region encountered along the ray.
  59. * now run this program as follows: @verbatim
  60. reshoot geom.g obj [obj...] < inputfile
  61. @endverbatim
  62. * and this will re-shoot all of the rays that the original program
  63. * shot, and compare the results.
  64. *
  65. * One of the basic assumptions is that the application structure
  66. * field a_onehit is set to zero in the original application, causing
  67. * all rays to be shot all the way through the geometry
  68. */
  69. #include "common.h"
  70. #include <stdlib.h>
  71. #include <stdio.h>
  72. #include <string.h>
  73. #include <math.h>
  74. #include <stddef.h>
  75. #include "vmath.h" /* vector math macros */
  76. #include "bu.h"
  77. #include "raytrace.h" /* librt interface definitions */
  78. #include "./rtuif.h"
  79. char *progname = "(noname)";
  80. /**
  81. * @struct shot
  82. * A description of a single shotline, and all the regions that were
  83. * hit by the shotline.
  84. */
  85. struct shot {
  86. point_t pt;
  87. vect_t dir;
  88. struct bu_list regions;
  89. };
  90. /**
  91. * @struct shot_sp
  92. * The parse table for a struct shot
  93. */
  94. static const struct bu_structparse shot_sp[] = {
  95. { "%f", 3, "Pnt", bu_offsetofarray(struct shot, pt), BU_STRUCTPARSE_FUNC_NULL},
  96. { "%f", 3, "Dir", bu_offsetofarray(struct shot, dir), BU_STRUCTPARSE_FUNC_NULL},
  97. {"", 0, (char *)0, 0, BU_STRUCTPARSE_FUNC_NULL }
  98. };
  99. /**
  100. * @struct reg_hit
  101. *
  102. * This describes the interaction of the ray with a single region
  103. */
  104. struct reg_hit {
  105. struct bu_list l; /* linked list membership */
  106. struct bu_vls regname; /* name of the region */
  107. struct bu_vls in_primitive; /* name of the primitive for the inbound hit */
  108. double indist; /* distance along ray to the inbound hit */
  109. struct bu_vls out_primitive; /* name of the primitive for the outbound hit */
  110. double outdist; /* distance along ray to the outbound hit */
  111. };
  112. static const struct bu_structparse reg_sp[] = {
  113. {"%V", 1, "region", bu_offsetof(struct reg_hit, regname), BU_STRUCTPARSE_FUNC_NULL },
  114. {"%V", 1, "in", bu_offsetof(struct reg_hit, in_primitive), BU_STRUCTPARSE_FUNC_NULL},
  115. {"%V", 1, "out", bu_offsetof(struct reg_hit, out_primitive), BU_STRUCTPARSE_FUNC_NULL},
  116. {"%f", 1, "indist", bu_offsetof(struct reg_hit, indist), BU_STRUCTPARSE_FUNC_NULL},
  117. {"%f", 1, "outdist", bu_offsetof(struct reg_hit, outdist), BU_STRUCTPARSE_FUNC_NULL},
  118. {"", 0, (char *)0, 0, BU_STRUCTPARSE_FUNC_NULL }
  119. };
  120. /**
  121. * U S A G E --- tell user how to invoke this program, then exit
  122. */
  123. void
  124. usage(char *s)
  125. {
  126. if (s) (void)fputs(s, stderr);
  127. bu_exit(1, "Usage: %s geom.g obj [obj...] < rayfile \n", progname);
  128. }
  129. /**
  130. * Process a single ray intersection list.
  131. * A pointer to this function is in the application structure a_hit field.
  132. * rt_shootray() calls this if geometry is hit by the ray. It passes the
  133. * application structure which describes the state of the world
  134. * (see raytrace.h), and a circular linked list of partitions,
  135. * each one describing one in and out segment of one region.
  136. * @return
  137. * integer value, typically 1. This value becomes the return value to rtshootray()
  138. */
  139. int
  140. hit(register struct application *ap, struct partition *PartHeadp, struct seg *segs)
  141. {
  142. /* see raytrace.h for all of these guys */
  143. register struct partition *pp;
  144. struct shot *sh = (struct shot *)ap->a_uptr;
  145. int status = 0;
  146. struct reg_hit *rh;
  147. struct bu_vls v;
  148. struct bu_vls result;
  149. struct valstruct {
  150. double val;
  151. } vs;
  152. static struct bu_structparse val_sp[] = {
  153. {"%f", 1, "val", bu_offsetof(struct valstruct, val)},
  154. };
  155. bu_vls_init(&v);
  156. bu_vls_init(&result);
  157. /* examine each partition until we get back to the head */
  158. rh = BU_LIST_FIRST(reg_hit, &sh->regions);
  159. for ( pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw ) {
  160. bu_vls_trunc(&result, 0);
  161. /* since the values were printed out using a %g format,
  162. * we have to do the same thing to the result to compare them
  163. */
  164. bu_vls_trunc(&v, 0);
  165. bu_vls_printf(&v, "val=%g", pp->pt_inhit->hit_dist);
  166. bu_struct_parse(&v, val_sp, (const char *)&vs);
  167. if (vs.val != rh->indist) {
  168. bu_vls_printf(&result, "\tinhit mismatch %g %g\n", pp->pt_inhit->hit_dist, rh->indist);
  169. status = 1;
  170. }
  171. bu_vls_trunc(&v, 0);
  172. bu_vls_printf(&v, "val=%g", pp->pt_outhit->hit_dist);
  173. bu_struct_parse(&v, val_sp, (const char *)&vs);
  174. if (vs.val != rh->outdist) {
  175. bu_vls_printf(&result, "\touthit mismatch %g %g\n", pp->pt_outhit->hit_dist, rh->outdist);
  176. status = 1;
  177. }
  178. /* check the region name */
  179. if (!BU_STR_EQUAL( pp->pt_regionp->reg_name, bu_vls_addr(&rh->regname) )) {
  180. /* region names don't match */
  181. bu_vls_printf(&result, "\tregion name mismatch %s %s\n", pp->pt_regionp->reg_name, bu_vls_addr(&rh->regname) );
  182. status = 1;
  183. }
  184. if ( !BU_STR_EQUAL(pp->pt_inseg->seg_stp->st_dp->d_namep, bu_vls_addr(&rh->in_primitive))) {
  185. bu_vls_printf(&result, "\tin primitive name mismatch %s %s\n", pp->pt_inseg->seg_stp->st_dp->d_namep, bu_vls_addr(&rh->in_primitive));
  186. status = 1;
  187. }
  188. if ( !BU_STR_EQUAL(pp->pt_outseg->seg_stp->st_dp->d_namep, bu_vls_addr(&rh->out_primitive))) {
  189. bu_vls_printf(&result, "\tout primitive name mismatch %s %s\n", pp->pt_outseg->seg_stp->st_dp->d_namep, bu_vls_addr(&rh->out_primitive));
  190. status = 1;
  191. }
  192. if (bu_vls_strlen(&result) > 0) {
  193. bu_log("Ray Pt %g,%g,%g Dir %g,%g,%g\n%V",
  194. V3ARGS(sh->pt),
  195. V3ARGS(sh->dir),
  196. &result);
  197. }
  198. rh = BU_LIST_NEXT(reg_hit, &rh->l);
  199. }
  200. /*
  201. * This value is returned by rt_shootray
  202. * a hit usually returns 1, miss 0.
  203. */
  204. return status;
  205. }
  206. /**
  207. * Function called when ray misses all geometry
  208. * A pointer to this function is stored in the application structure
  209. * field a_miss. rt_shootray() will call this when the ray misses all geometry.
  210. * it passees the application structure.
  211. * @return
  212. * Typically 0, and becomes the return value from rt_shootray()
  213. */
  214. int
  215. miss(register struct application *ap)
  216. {
  217. return 0;
  218. }
  219. /**
  220. * Print a shot. Mostly a debugging routine.
  221. *
  222. */
  223. void
  224. pr_shot(struct shot *sh)
  225. {
  226. struct reg_hit *rh;
  227. /* shoot the old ray */
  228. bu_struct_print("shooting", shot_sp, (const char *)sh);
  229. for (BU_LIST_FOR(rh, reg_hit, &sh->regions)) {
  230. bu_struct_print("", reg_sp, (const char *)rh);
  231. }
  232. }
  233. /**
  234. * Re-shoot a ray
  235. * The ray described by the parametry sh
  236. *
  237. * @param sh a pointer to a struct shot describing the ray to shoot and expected results
  238. * @param ap a pointer to a struct application
  239. * @return
  240. * integer value indicating if there was a difference
  241. */
  242. int
  243. do_shot(struct shot *sh, struct application *ap)
  244. {
  245. struct reg_hit *rh;
  246. int status;
  247. VMOVE(ap->a_ray.r_pt, sh->pt);
  248. VMOVE(ap->a_ray.r_dir, sh->dir);
  249. ap->a_uptr = (genptr_t)sh;
  250. ap->a_hit = hit;
  251. ap->a_miss = miss;
  252. status = rt_shootray( ap ); /* do it */
  253. /* clean up */
  254. while (BU_LIST_WHILE(rh, reg_hit, &sh->regions)) {
  255. BU_LIST_DEQUEUE( &(rh->l) );
  256. bu_vls_free(&rh->regname);
  257. bu_vls_free(&rh->in_primitive);
  258. bu_vls_free(&rh->out_primitive);
  259. bu_free(rh, "");
  260. }
  261. return status;
  262. }
  263. /**
  264. * Load the database, parse the input, and shoot the rays
  265. * @return
  266. * integer flag value indicating whether any differences were detected. 0 = none, !0 = different
  267. */
  268. int
  269. main(int argc, char **argv)
  270. {
  271. /* every application needs one of these */
  272. struct application ap;
  273. static struct rt_i *rtip; /* rt_dirbuild returns this */
  274. char idbuf[2048] = {0}; /* First ID record info */
  275. int arg_count;
  276. int status = 0;
  277. struct bu_vls buf;
  278. struct shot sh;
  279. progname = argv[0];
  280. if ( argc < 3 ) {
  281. usage("insufficient args\n");
  282. }
  283. /*
  284. * Load database.
  285. * rt_dirbuild() returns an "instance" pointer which describes
  286. * the database to be ray traced. It also gives you back the
  287. * title string in the header (ID) record.
  288. */
  289. if ( (rtip=rt_dirbuild(argv[1], idbuf, sizeof(idbuf))) == RTI_NULL ) {
  290. bu_exit(2, "rtexample: rt_dirbuild failure\n");
  291. }
  292. /* intialize the application structure to all zeros */
  293. RT_APPLICATION_INIT(&ap);
  294. ap.a_rt_i = rtip; /* your application uses this instance */
  295. /* Walk trees.
  296. * Here you identify any object trees in the database that you
  297. * want included in the ray trace.
  298. */
  299. while ( argc > 2 ) {
  300. if ( rt_gettree(rtip, argv[2]) < 0 )
  301. fprintf(stderr, "rt_gettree(%s) FAILED\n", argv[0]);
  302. argc--;
  303. argv++;
  304. }
  305. /*
  306. * This next call gets the database ready for ray tracing.
  307. * (it precomputes some values, sets up space partitioning, etc.)
  308. */
  309. rt_prep_parallel(rtip, 1);
  310. bu_vls_init(&buf);
  311. memset((void *)&sh, 0, sizeof(sh));
  312. BU_LIST_INIT(&sh.regions);
  313. while (bu_vls_gets(&buf, stdin) >= 0) {
  314. char *p = bu_vls_addr(&buf);
  315. switch (*p) {
  316. case 'P' :
  317. {
  318. if (BU_LIST_NON_EMPTY(&sh.regions)) {
  319. status |= do_shot(&sh, &ap);
  320. }
  321. if (bu_struct_parse(&buf, shot_sp, (const char *)&sh)) {
  322. bu_exit(EXIT_FAILURE, "error parsing pt");
  323. }
  324. break;
  325. }
  326. case 'D' :
  327. {
  328. if (bu_struct_parse(&buf, shot_sp, (const char *)&sh)) {
  329. bu_exit(EXIT_FAILURE, "error parsing dir");
  330. }
  331. break;
  332. }
  333. default:
  334. {
  335. struct reg_hit *rh = bu_calloc(1, sizeof (struct reg_hit), "");
  336. if (bu_struct_parse(&buf, reg_sp, (const char *)rh)) {
  337. bu_log("Error parsing region %s\nSkipping to next line\n",
  338. bu_vls_addr(&buf));
  339. }
  340. BU_LIST_APPEND(&sh.regions, &rh->l);
  341. break;
  342. }
  343. }
  344. bu_vls_trunc(&buf, 0);
  345. }
  346. status |= do_shot(&sh, &ap);
  347. return status;
  348. }
  349. /*
  350. * Local Variables:
  351. * mode: C
  352. * tab-width: 8
  353. * indent-tabs-mode: t
  354. * c-file-style: "stroustrup"
  355. * End:
  356. * ex: shiftwidth=4 tabstop=8
  357. */