Revision: 76106
http://sourceforge.net/p/brlcad/code/76106
Author: starseeker
Date: 2020-06-11 00:33:24 +0000 (Thu, 11 Jun 2020)
Log Message:
-----------
Start working on grid, which is the heart of the implementation. This will be
the trickiest part to adapt away from global variable usage.
Modified Paths:
--------------
brlcad/branches/bioh/src/burst2/CMakeLists.txt
brlcad/branches/bioh/src/burst2/burst.cpp
brlcad/branches/bioh/src/burst2/burst.h
brlcad/branches/bioh/src/burst2/execute.cpp
Added Paths:
-----------
brlcad/branches/bioh/src/burst2/grid.cpp
Modified: brlcad/branches/bioh/src/burst2/CMakeLists.txt
===================================================================
--- brlcad/branches/bioh/src/burst2/CMakeLists.txt 2020-06-10 19:47:33 UTC
(rev 76105)
+++ brlcad/branches/bioh/src/burst2/CMakeLists.txt 2020-06-11 00:33:24 UTC
(rev 76106)
@@ -12,8 +12,9 @@
set(burst_SOURCES
burst.cpp
+ execute.cpp
+ #grid.cpp
idents.cpp
- execute.cpp
${LDIR}/utf8.c
${LDIR}/linenoise.c
)
@@ -24,6 +25,7 @@
CMakeLists.txt
burst.h
burst.format
+ grid.cpp
)
CMAKEFILES(${burst_ignore})
Modified: brlcad/branches/bioh/src/burst2/burst.cpp
===================================================================
--- brlcad/branches/bioh/src/burst2/burst.cpp 2020-06-10 19:47:33 UTC (rev
76105)
+++ brlcad/branches/bioh/src/burst2/burst.cpp 2020-06-11 00:33:24 UTC (rev
76106)
@@ -112,7 +112,6 @@
s->reportoverlaps = DFL_OVERLAPS;
s->reqburstair = 1;
s->shotburst = 0;
- s->tty = 1;
s->userinterrupt = 0;
memset(s->airfile, 0, LNBUFSZ);
memset(s->armorfile, 0, LNBUFSZ);
Modified: brlcad/branches/bioh/src/burst2/burst.h
===================================================================
--- brlcad/branches/bioh/src/burst2/burst.h 2020-06-10 19:47:33 UTC (rev
76105)
+++ brlcad/branches/bioh/src/burst2/burst.h 2020-06-11 00:33:24 UTC (rev
76106)
@@ -106,7 +106,6 @@
int reportoverlaps; /* if true, overlaps are reported */
int reqburstair; /* if true, burst air required for shotburst */
int shotburst; /* if true, burst along shotline */
- int tty; /* if true, full screen display is used */
int userinterrupt; /* has the ray trace been interrupted */
char airfile[LNBUFSZ]; /* input file name for burst air ids */
@@ -204,9 +203,17 @@
void burst_state_init(struct burst_state *s);
+int findIdents(int ident, struct bu_ptbl *idpl);
int readIdents(struct bu_ptbl *idlist, const char *fname);
int readColors(struct bu_ptbl *idlist, const char *fname);
+struct colors *findColors(int ident, struct bu_ptbl *colp);
+
+
+void gridModel(struct burst_state *s);
+void gridInit(struct burst_state *s);
+void spallInit(struct burst_state *s);
+
#endif /* BURST_BURST_H */
/*
Modified: brlcad/branches/bioh/src/burst2/execute.cpp
===================================================================
--- brlcad/branches/bioh/src/burst2/execute.cpp 2020-06-10 19:47:33 UTC (rev
76105)
+++ brlcad/branches/bioh/src/burst2/execute.cpp 2020-06-11 00:33:24 UTC (rev
76106)
@@ -99,11 +99,11 @@
rt_prep(s->rtip);
prntTimer(s, "prep");
}
- //gridInit();
+ //gridInit(s);
if (s->nriplevels > 0) {
- //spallInit();
+ //spallInit(s);
}
- //gridModel();
+ //gridModel(s);
return;
}
Added: brlcad/branches/bioh/src/burst2/grid.cpp
===================================================================
--- brlcad/branches/bioh/src/burst2/grid.cpp (rev 0)
+++ brlcad/branches/bioh/src/burst2/grid.cpp 2020-06-11 00:33:24 UTC (rev
76106)
@@ -0,0 +1,1669 @@
+/* G R I D . C
+ * BRL-CAD
+ *
+ * Copyright (c) 2004-2020 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; see the file named COPYING for more
+ * information.
+ *
+ */
+/** @file burst/grid.c
+ *
+ */
+
+#include "common.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <math.h>
+
+#include "vmath.h"
+#include "bn.h"
+#include "raytrace.h"
+#include "fb.h"
+#include "bn/plot3.h"
+
+#include "./burst.h"
+
+#define ASNBIT(w, b) (w = (b))
+#define SETBIT(w, b) (w |= (b))
+#define CLRBIT(w, b) (w &= ~(b))
+#define TSTBIT(w, b) ((w)&(b))
+
+#define C_MAIN 0
+#define C_CRIT 1
+
+/* colors for UNIX plot files */
+#define R_GRID 255 /* grid - yellow */
+#define G_GRID 255
+#define B_GRID 0
+
+#define R_BURST 255 /* burst cone - red */
+#define G_BURST 0
+#define B_BURST 0
+
+#define R_OUTAIR 100 /* outside air - light blue */
+#define G_OUTAIR 100
+#define B_OUTAIR 255
+
+#define R_INAIR 100 /* inside air - light green */
+#define G_INAIR 255
+#define B_INAIR 100
+
+#define R_COMP 0 /* component (default) - blue */
+#define G_COMP 0
+#define B_COMP 255
+
+#define R_CRIT 255 /* critical component (default) - purple */
+#define G_CRIT 0
+#define B_CRIT 255
+
+#define LOS_TOL 0.1
+#define VEC_TOL 0.001
+#define OVERLAP_TOL 0.25 /* thinner overlaps not reported */
+#define EXIT_AIR 9 /* exit air is called 09 air */
+#define OUTSIDE_AIR 1 /* outside air is called 01 air */
+
+#define Air(rp) ((rp)->reg_aircode > 0)
+#define DiffAir(rp, sp) ((rp)->reg_aircode != (sp)->reg_aircode)
+#define SameAir(rp, sp) ((rp)->reg_aircode == (sp)->reg_aircode)
+#define SameCmp(rp, sp) ((rp)->reg_regionid == (sp)->reg_regionid)
+#define OutsideAir(rp) ((rp)->reg_aircode == OUTSIDE_AIR)
+#define InsideAir(rp) (Air(rp)&& !OutsideAir(rp))
+
+
+#define DEBUG_GRID 0
+#define DEBUG_SHOT 1
+
+typedef struct pt_queue Pt_Queue;
+struct pt_queue
+{
+ struct partition *q_part;
+ Pt_Queue *q_next;
+};
+#define PT_Q_NULL (Pt_Queue *) 0
+
+/* local communication with multitasking process */
+static int currshot; /* current shot index */
+static int lastshot; /* final shot index */
+
+static fastf_t viewdir[3]; /* direction of attack */
+static fastf_t delta; /* angular delta ray of spall cone */
+static fastf_t comphi; /* angle between ring and cone axis */
+static fastf_t phiinc; /* angle between concentric rings */
+
+static fastf_t cantdelta[3]; /* delta ray specified by yaw and pitch */
+
+static struct application ag; /* global application structure (zeroed out) */
+
+/*
+ void colorPartition(struct region *regp, int type)
+
+ If user has asked for a UNIX plot write a color command to
+ the output stream plotfp which represents the region specified
+ by regp.
+*/
+void
+colorPartition(struct burst_state *s, struct region *regp, int type)
+{
+ struct colors *colorp;
+ if (!bu_vls_strlen(&s->plotfile))
+ return;
+ assert(s->plotfp != NULL);
+ bu_semaphore_acquire(BU_SEM_SYSCALL);
+ switch (type) {
+ case C_CRIT :
+ if ((colorp = findColors(regp->reg_regionid, &s->colorids)) ==
NULL) {
+ pl_color(s->plotfp, R_CRIT, G_CRIT, B_CRIT);
+ } else {
+ pl_color(s->plotfp,
+ (int) colorp->c_rgb[0],
+ (int) colorp->c_rgb[1],
+ (int) colorp->c_rgb[2]
+ );
+ }
+ break;
+ case C_MAIN :
+ if ((colorp = findColors(regp->reg_regionid, &s->colorids)) ==
NULL) {
+ if (InsideAir(regp)) {
+ pl_color(s->plotfp, R_INAIR, G_INAIR, B_INAIR);
+ } else {
+ if (Air(regp)) {
+ pl_color(s->plotfp, R_OUTAIR, G_OUTAIR, B_OUTAIR);
+ } else {
+ pl_color(s->plotfp, R_COMP, G_COMP, B_COMP);
+ }
+ }
+ } else {
+ pl_color(s->plotfp,
+ (int) colorp->c_rgb[0],
+ (int) colorp->c_rgb[1],
+ (int) colorp->c_rgb[2]
+ );
+ }
+ break;
+ default :
+ //bu_log("colorPartition: bad type %d.\n", type);
+ break;
+ }
+ bu_semaphore_release(BU_SEM_SYSCALL);
+ return;
+}
+
+static void
+view_pix(struct burst_state *s, struct application *ap)
+{
+ bu_semaphore_acquire(BU_SEM_SYSCALL);
+ if (!TSTBIT(s->firemode, FM_BURST)) {
+ prntGridOffsets(ap->a_x, ap->a_y);
+ }
+ bu_semaphore_release(BU_SEM_SYSCALL);
+ return;
+}
+
+
+
+/*
+ void enforceLOS(struct application *ap,
+ struct partition *pt_headp)
+
+ Enforce the line-of-sight tolerance by deleting partitions that are
+ too thin.
+*/
+static void
+enforceLOS(struct application *ap, struct partition *pt_headp)
+{
+ struct partition *pp;
+ for (pp = pt_headp->pt_forw; pp != pt_headp;) {
+ struct partition *nextpp = pp->pt_forw;
+ if (pp->pt_outhit->hit_dist - pp->pt_inhit->hit_dist
+ <= LOS_TOL) {
+ DEQUEUE_PT(pp);
+ FREE_PT(pp, ap->a_resource);
+ }
+ pp = nextpp;
+ }
+ return;
+}
+
+
+/*
+ int f_BurstHit(struct application *ap, struct partition *pt_headp)
+
+ This routine handles all output associated with burst ray intersections.
+
+ RETURN CODES: -1 indicates a fatal error, and fatalerror will be
+ set to 1. A positive number is interpreted as the count of critical
+ component intersections. A value of 0 would indicate that zero
+ critical components were encountered.
+*/
+static int
+f_BurstHit(struct application *ap, struct partition *pt_headp, struct seg
*UNUSED(segp))
+{
+ struct burst_state *s = (struct burst_state *)ap->a_uptr;
+ Pt_Queue *qshield = PT_Q_NULL;
+ struct partition *cpp, *spp;
+ int nbar;
+ int ncrit = 0;
+#ifdef VDEBUG
+ prntDbgPartitions(ap, pt_headp, "f_BurstHit: initial partitions");
+#endif
+ /* Find first barrier in front of the burst point. */
+ for (spp = pt_headp->pt_forw;
+ spp != pt_headp
+ && spp->pt_outhit->hit_dist < 0.1;
+ spp = spp->pt_forw
+ )
+ ;
+ for (cpp = spp, nbar = 0;
+ cpp != pt_headp && nbar <= s->nbarriers;
+ cpp = cpp->pt_forw
+ ) {
+ struct region *regp = cpp->pt_regionp;
+ struct xray *rayp = &ap->a_ray;
+ if (Air(regp))
+ continue; /* Air doesn't matter here. */
+ if (findIdents(regp->reg_regionid, &s->critids)) {
+ fastf_t entrynorm[3], exitnorm[3];
+ if (ncrit == 0)
+ prntRayHeader(ap->a_ray.r_dir, viewdir,
+ ap->a_user);
+ /* Output queued non-critical components. */
+ prntShieldComp(ap, pt_headp, qshield);
+ qFree(qshield);
+ qshield = PT_Q_NULL; /* queue empty */
+
+ /* Output critical component intersection;
+ prntRegionHdr fills in hit entry/exit normals. */
+ prntRegionHdr(ap, pt_headp, cpp, entrynorm, exitnorm);
+ colorPartition(regp, C_CRIT);
+ plotPartition(cpp->pt_inhit, cpp->pt_outhit);
+
+ if (fbfile[0] != NUL && ncrit == 0)
+ /* first hit on critical component */
+ lgtModel(ap, cpp, cpp->pt_inhit, rayp,
+ entrynorm);
+ ncrit++;
+ } else
+ /* Queue up shielding components until we hit a critical one. */
+ if (cpp->pt_forw != pt_headp) {
+ if (! qAdd(cpp, &qshield)) {
+ fatalerror = 1;
+ return -1;
+ }
+ nbar++;
+ }
+ }
+ qFree(qshield);
+ if (ncrit == 0)
+ return ap->a_miss(ap);
+ else
+ return ncrit;
+}
+
+
+/*
+ int f_HushOverlap(struct application *ap, struct partition *pp,
+ struct region *reg1, struct region *reg2,
+ struct partition *pheadp)
+
+ Do not report diagnostics about individual overlaps, but keep count
+ of significant ones (at least as thick as OVERLAP_TOL).
+
+ Returns -
+ 0 to eliminate partition with overlap entirely
+ 1 to retain partition in output list, claimed by reg1
+ 2 to retain partition in output list, claimed by reg2
+*/
+/*ARGSUSED*/
+static int
+f_HushOverlap(struct application *ap, struct partition *pp, struct region
*reg1, struct region *reg2, struct partition *pheadp)
+{
+ fastf_t depth;
+ depth = pp->pt_outhit->hit_dist - pp->pt_inhit->hit_dist;
+ if (depth >= OVERLAP_TOL)
+ noverlaps++;
+
+ return rt_defoverlap(ap, pp, reg1, reg2, pheadp);
+}
+
+
+/*
+ int f_Overlap(struct application *ap, struct partition *pp,
+ struct region *reg1, struct region *reg2,
+ struct partition *pheadp)
+
+ Do report diagnostics and keep count of individual overlaps
+ that are at least as thick as OVERLAP_TOL.
+
+ Returns -
+ 0 to eliminate partition with overlap entirely
+ 1 to retain partition in output list, claimed by reg1
+ 2 to retain partition in output list, claimed by reg2
+*/
+/*ARGSUSED*/
+static int
+f_Overlap(struct application *ap, struct partition *pp, struct region *reg1,
struct region *reg2, struct partition *pheadp)
+{
+ fastf_t depth;
+ point_t pt;
+ depth = pp->pt_outhit->hit_dist - pp->pt_inhit->hit_dist;
+ if (depth >= OVERLAP_TOL) {
+ noverlaps++;
+
+ VJOIN1(pt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist,
+ ap->a_ray.r_dir);
+ brst_log("OVERLAP:\n");
+ brst_log("reg=%s isol=%s, \n",
+ reg1->reg_name, pp->pt_inseg->seg_stp->st_name
+ );
+ brst_log("reg=%s osol=%s, \n",
+ reg2->reg_name, pp->pt_outseg->seg_stp->st_name
+ );
+ brst_log("depth %.2fmm at (%g, %g, %g) x%d y%d lvl%d purpose=%s\n",
+ depth,
+ pt[X], pt[Y], pt[Z],
+ ap->a_x, ap->a_y, ap->a_level, ap->a_purpose
+ );
+ }
+
+ return rt_defoverlap(ap, pp, reg1, reg2, pheadp);
+}
+
+
+/*
+ int f_ShotHit(struct application *ap, struct partition *pt_headp)
+
+ This routine is called when a shotline hits the model. All output
+ associated with the main penetrator path is printed here. If line-
+ of-sight bursting is requested, burst point gridding is spawned by
+ a call to burstPoint() which dispatches the burst ray task burstRay(),
+ a recursive call to the ray tracer.
+
+ RETURN CODES: 0 would indicate a failure in an application routine
+ handed to rt_shootray() by burstRay(). Otherwise, 1 is returned.
+*/
+static int
+f_ShotHit(struct application *ap, struct partition *pt_headp, struct seg
*UNUSED(segp))
+{
+ struct partition *pp;
+ struct partition *bp = PT_NULL;
+ vect_t burstnorm = VINIT_ZERO; /* normal at burst point */
+#if DEBUG_GRID
+ brst_log("f_ShotHit\n");
+ for (pp = pt_headp->pt_forw; pp != pt_headp; pp = pp->pt_forw)
+ brst_log("\tregion is '%s', \tid=%d\taircode=%d\n",
+ pp->pt_regionp->reg_name,
+ (int) pp->pt_regionp->reg_regionid,
+ (int) pp->pt_regionp->reg_aircode);
+#endif
+ /* Output cell identification. */
+ prntCellIdent(ap);
+ /* Color cell if making frame buffer image. */
+ if (fbfile[0] != NUL)
+ paintCellFb(ap, pixtarg, zoom == 1 ? pixblack : pixbkgr);
+
+ /* First delete thin partitions. */
+ enforceLOS(ap, pt_headp);
+
+ /* Output ray intersections. This code is extremely cryptic because
+ it is dealing with errors in the geometry, where there is
+ either adjacent airs of differing types, or voids (gaps)
+ in the description. In the case of adjacent airs, phantom
+ armor must be output. For voids, outside air is the default
+ (everyone knows that air rushes to fill a vacuum), so we
+ must pretend that it is there. Outside air is also called
+ 01 air because its aircode equals 1. Please tread carefully
+ on the code within this loop, it is filled with special
+ cases involving adjacency of partitions both real (explicit)
+ and imagined (implicit).
+ */
+ for (pp = pt_headp->pt_forw; pp != pt_headp; pp = pp->pt_forw) {
+ int voidflag = 0;
+ struct partition *np = pp->pt_forw;
+ struct partition *cp;
+ struct region *regp = pp->pt_regionp;
+ struct region *nregp = pp->pt_forw->pt_regionp;
+
+ /* Fill in entry and exit points into hit structures. */
+ {
+ struct hit *ihitp = pp->pt_inhit;
+ struct hit *ohitp = pp->pt_outhit;
+ struct xray *rayp = &ap->a_ray;
+ VJOIN1(ihitp->hit_point, rayp->r_pt, ihitp->hit_dist,
+ rayp->r_dir);
+ VJOIN1(ohitp->hit_point, rayp->r_pt, ohitp->hit_dist,
+ rayp->r_dir);
+ colorPartition(regp, C_MAIN);
+ plotPartition(ihitp, ohitp);
+ }
+
+ /* Check for voids. */
+ if (np != pt_headp) {
+ fastf_t los = 0.0;
+
+#if DEBUG_GRID
+ brst_log("\tprocessing region '%s', \tid=%d\taircode=%d\n",
+ pp->pt_regionp->reg_name,
+ (int) pp->pt_regionp->reg_regionid,
+ (int) pp->pt_regionp->reg_aircode);
+ brst_log("\tcheck for voids\n");
+#endif
+ los = np->pt_inhit->hit_dist -
+ pp->pt_outhit->hit_dist;
+#if DEBUG_GRID
+ brst_log("\tlos=%g tolerance=%g\n",
+ los, LOS_TOL);
+#endif
+ voidflag = (los > LOS_TOL);
+ /* If the void occurs adjacent to explicit outside
+ air, extend the outside air to fill it. */
+ if (OutsideAir(np->pt_regionp)) {
+#if DEBUG_GRID
+ brst_log("\t\toutside air\n");
+#endif
+ if (voidflag) {
+ np->pt_inhit->hit_dist =
+ pp->pt_outhit->hit_dist;
+ voidflag = 0;
+ }
+ /* Keep going until we are past 01 air. */
+ for (cp = np->pt_forw;
+ cp != pt_headp;
+ cp = cp->pt_forw) {
+ if (OutsideAir(cp->pt_regionp))
+ /* Include outside air. */
+ np->pt_outhit->hit_dist =
+ cp->pt_outhit->hit_dist;
+ else
+ if (cp->pt_inhit->hit_dist -
+ np->pt_outhit->hit_dist
+ > LOS_TOL)
+ /* Include void following
+ outside air. */
+ np->pt_outhit->hit_dist =
+ cp->pt_inhit->hit_dist;
+ else
+ break;
+ }
+ }
+ }
+ /* Merge adjacent inside airs of same type. */
+ if (np != pt_headp && InsideAir(np->pt_regionp)) {
+#if DEBUG_GRID
+ brst_log("\tmerging inside airs\n");
+#endif
+ for (cp = np->pt_forw;
+ cp != pt_headp;
+ cp = cp->pt_forw) {
+ if (InsideAir(cp->pt_regionp)
+ && SameAir(np->pt_regionp, cp->pt_regionp)
+ && cp->pt_inhit->hit_dist -
+ np->pt_outhit->hit_dist
+ <= LOS_TOL)
+ np->pt_outhit->hit_dist =
+ cp->pt_outhit->hit_dist;
+ else
+ break;
+ }
+ }
+
+ /* Check for possible phantom armor before internal air,
+ that is if it is the first thing hit. */
+ if (pp->pt_back == pt_headp && InsideAir(regp)) {
+ /* If adjacent partitions are the same air, extend
+ the first on to include them. */
+#if DEBUG_GRID
+ brst_log("\tphantom armor before internal air\n");
+#endif
+ for (cp = np; cp != pt_headp; cp = cp->pt_forw) {
+ if (InsideAir(cp->pt_regionp)
+ && SameAir(regp, cp->pt_regionp)
+ && cp->pt_inhit->hit_dist -
+ pp->pt_outhit->hit_dist
+ <= LOS_TOL)
+ pp->pt_outhit->hit_dist =
+ cp->pt_outhit->hit_dist;
+ else
+ break;
+
+ }
+
+ prntPhantom(pp->pt_inhit, (int) regp->reg_aircode);
+ } else
+ if (! Air(regp)) {
+ /* If we have a component, output it. */
+ fastf_t entrynorm[3]; /* normal at entry */
+ fastf_t exitnorm[3]; /* normal at exit */
+ /* Get entry normal. */
+ getRtHitNorm(pp->pt_inhit, pp->pt_inseg->seg_stp,
+ &ap->a_ray, (int) pp->pt_inflip, entrynorm);
+ (void) chkEntryNorm(pp, &ap->a_ray, entrynorm,
+ "shotline entry normal");
+ /* Get exit normal. */
+ getRtHitNorm(pp->pt_outhit, pp->pt_outseg->seg_stp,
+ &ap->a_ray, (int) pp->pt_outflip, exitnorm);
+ (void) chkExitNorm(pp, &ap->a_ray, exitnorm,
+ "shotline exit normal");
+
+#if DEBUG_GRID
+ brst_log("\twe have a component\n");
+#endif
+ /* In the case of fragmenting munitions, a hit on any
+ component will cause a burst point. */
+ if (bp == PT_NULL && bdist > 0.0) {
+ bp = pp; /* exterior burst */
+ VMOVE(burstnorm, exitnorm);
+ }
+
+ /* If there is a void, output 01 air as space. */
+ if (voidflag) {
+#if DEBUG_GRID
+ brst_log("\t\tthere is a void, %s\n",
+ "so outputting 01 air");
+#endif
+ if (bp == PT_NULL && ! reqburstair
+ && findIdents(regp->reg_regionid,
+ &armorids)) {
+ /* Bursting on armor/void (ouch). */
+ bp = pp;
+ VMOVE(burstnorm, exitnorm);
+ }
+ prntSeg(ap, pp, OUTSIDE_AIR,
+ entrynorm, exitnorm, pp == bp);
+ } else
+ /* If air explicitly follows, output space code. */
+ if (np != pt_headp && Air(nregp)) {
+ /* Check for interior burst point. */
+#if DEBUG_GRID
+ brst_log("\t\texplicit air follows\n");
+#endif
+ if (bp == PT_NULL && bdist <= 0.0
+ && findIdents(regp->reg_regionid,
+ &armorids)
+ && (! reqburstair
+ || findIdents(nregp->reg_aircode,
+ &airids))
+ ) {
+ bp = pp; /* interior burst */
+ VMOVE(burstnorm, exitnorm);
+ }
+ prntSeg(ap, pp, nregp->reg_aircode,
+ entrynorm, exitnorm, pp == bp);
+ } else
+ if (np == pt_headp) {
+ /* Last component gets 09 air. */
+#if DEBUG_GRID
+ brst_log("\t\tlast component\n");
+#endif
+ prntSeg(ap, pp, EXIT_AIR,
+ entrynorm, exitnorm, pp == bp);
+ } else
+ /* No air follows component. */
+ if (SameCmp(regp, nregp)) {
+#if DEBUG_GRID
+ brst_log("\t\tmerging adjacent components\n");
+#endif
+ /* Merge adjacent components with same
+ idents. */
+ *np->pt_inhit = *pp->pt_inhit;
+ np->pt_inseg = pp->pt_inseg;
+ np->pt_inflip = pp->pt_inflip;
+ continue;
+ } else {
+#if DEBUG_GRID
+ brst_log("\t\tdifferent component follows\n");
+#endif
+ prntSeg(ap, pp, 0,
+ entrynorm, exitnorm, pp == bp);
+ /* component follows */
+ }
+ }
+ /* Check for adjacency of differing airs, implicit or
+ explicit and output phantom armor as needed. */
+ if (InsideAir(regp)) {
+#if DEBUG_GRID
+ brst_log("\tcheck for adjacency of differing airs; inside air\n");
+#endif
+ /* Inside air followed by implicit outside air. */
+ if (voidflag)
+ prntPhantom(pp->pt_outhit, OUTSIDE_AIR);
+ }
+ /* Check next partition for adjacency problems. */
+ if (np != pt_headp) {
+#if DEBUG_GRID
+ brst_log("\tcheck next partition for adjacency\n");
+#endif
+ /* See if inside air follows impl. outside air. */
+ if (voidflag && InsideAir(nregp)) {
+#if DEBUG_GRID
+ brst_log("\t\tinside air follows impl. outside air\n");
+#endif
+ prntPhantom(np->pt_inhit, nregp->reg_aircode);
+ } else
+ /* See if differing airs are adjacent. */
+ if (! voidflag
+ && Air(regp)
+ && Air(nregp)
+ && DiffAir(nregp, regp)
+ ) {
+#if DEBUG_GRID
+ brst_log("\t\tdiffering airs are adjacent\n");
+#endif
+ prntPhantom(np->pt_inhit, (int) nregp->reg_aircode);
+ }
+ }
+ /* Output phantom armor if internal air is last hit. */
+ if (np == pt_headp && InsideAir(regp)) {
+#if DEBUG_GRID
+ brst_log("\tinternal air last hit\n");
+#endif
+ prntPhantom(pp->pt_outhit, EXIT_AIR);
+ }
+ }
+ if (nriplevels == 0)
+ return 1;
+
+ if (bp != PT_NULL) {
+ fastf_t burstpt[3];
+ /* This is a burst point, calculate coordinates. */
+ if (bdist > 0.0) {
+ /* Exterior burst point (i.e. case-fragmenting
+ munition with contact-fuzed set-back device):
+ location is bdist prior to entry point. */
+ VJOIN1(burstpt, bp->pt_inhit->hit_point, -bdist,
+ ap->a_ray.r_dir);
+ } else
+ if (bdist < 0.0) {
+ /* Interior burst point (i.e. case-fragment
+ munition with delayed fuzing): location is
+ the magnitude of bdist beyond the exit
+ point. */
+ VJOIN1(burstpt, bp->pt_outhit->hit_point, -bdist,
+ ap->a_ray.r_dir);
+ } else /* Interior burst point: no fuzing offset. */
+ VMOVE(burstpt, bp->pt_outhit->hit_point);
+
+ /* Only generate burst rays if nspallrays is greater than
+ zero. */
+ if (nspallrays < 1)
+ return 1;
+
+ return burstPoint(ap, burstnorm, burstpt);
+ }
+ return 1;
+}
+
+
+/*
+ void getRtHitNorm(struct hit *hitp, struct soltab *stp,
+ struct xray *rayp, int flipped, fastf_t normvec[3])
+
+ Fill normal and hit point into hit struct and if the flipped
+ flag is set, reverse the normal. Return a private copy of the
+ flipped normal in normvec. NOTE: the normal placed in the hit
+ struct should not be modified (i.e. reversed) by the application
+ because it can be instanced by other solids.
+*/
+void
+getRtHitNorm(struct hit *hitp, struct soltab *stp, struct xray *UNUSED(rayp),
int flipped, fastf_t normvec[3])
+{
+ RT_HIT_NORMAL(normvec, hitp, stp, rayp, flipped);
+}
+
+
+int
+chkEntryNorm(struct partition *pp, struct xray *rayp, fastf_t normvec[3], char
*purpose)
+{
+ fastf_t f;
+ static int flipct = 0;
+ static int totalct = 0;
+ struct soltab *stp = pp->pt_inseg->seg_stp;
+ int ret = 1;
+ totalct++;
+ /* Dot product of ray direction with normal *should* be negative. */
+ f = VDOT(rayp->r_dir, normvec);
+ if (ZERO(f)) {
+#ifdef DEBUG
+ brst_log("chkEntryNorm: near 90 degree obliquity.\n");
+ brst_log("\tPnt %g, %g, %g\n\tDir %g, %g, %g\n\tNorm %g, %g, %g.\n",
+ rayp->r_pt[X], rayp->r_pt[Y], rayp->r_pt[Z],
+ rayp->r_dir[X], rayp->r_dir[Y], rayp->r_dir[Z],
+ normvec[X], normvec[Y], normvec[Z]);
+#endif
+ ret = 0;
+ }
+ if (f > 0.0) {
+ flipct++;
+ brst_log("Fixed flipped entry normal:\n");
+ brst_log("\tregion \"%s\" solid \"%s\" type %d \"%s\".\n",
+ pp->pt_regionp->reg_name, stp->st_name,
+ stp->st_id, purpose);
+#ifdef DEBUG
+ brst_log("\tPnt %g, %g, %g\n\tDir %g, %g, %g\n\tNorm %g, %g, %g.\n",
+ rayp->r_pt[X], rayp->r_pt[Y], rayp->r_pt[Z],
+ rayp->r_dir[X], rayp->r_dir[Y], rayp->r_dir[Z],
+ normvec[X], normvec[Y], normvec[Z]);
+ brst_log("\tDist %g Hit Pnt %g, %g, %g\n",
+ pp->pt_inhit->hit_dist,
+ pp->pt_inhit->hit_point[X],
+ pp->pt_inhit->hit_point[Y],
+ pp->pt_inhit->hit_point[Z]);
+ brst_log("\t%d of %d normals flipped.\n", flipct, totalct);
+#endif
+ VSCALE(normvec, normvec, -1.0);
+ ret = 0;
+ }
+ return ret;
+}
+
+
+int
+chkExitNorm(struct partition *pp, struct xray *rayp, fastf_t normvec[3], char
*purpose)
+{
+ fastf_t f;
+ static int flipct = 0;
+ static int totalct = 0;
+ struct soltab *stp = pp->pt_outseg->seg_stp;
+ int ret = 1;
+ totalct++;
+ /* Dot product of ray direction with normal *should* be positive. */
+ f = VDOT(rayp->r_dir, normvec);
+ if (ZERO(f)) {
+#ifdef DEBUG
+ brst_log("chkExitNorm: near 90 degree obliquity.\n");
+ brst_log("\tPnt %g, %g, %g\n\tDir %g, %g, %g\n\tNorm %g, %g, %g.\n",
+ rayp->r_pt[X], rayp->r_pt[Y], rayp->r_pt[Z],
+ rayp->r_dir[X], rayp->r_dir[Y], rayp->r_dir[Z],
+ normvec[X], normvec[Y], normvec[Z]);
+#endif
+ ret = 0;
+ }
+ if (f < 0.0) {
+ flipct++;
+ brst_log("Fixed flipped exit normal:\n");
+ brst_log("\tregion \"%s\" solid \"%s\" type %d \"%s\".\n",
+ pp->pt_regionp->reg_name, stp->st_name,
+ stp->st_id, purpose);
+#ifdef DEBUG
+ brst_log("\tPnt %g, %g, %g\n\tDir %g, %g, %g\n\tNorm %g, %g, %g.\n",
+ rayp->r_pt[X], rayp->r_pt[Y], rayp->r_pt[Z],
+ rayp->r_dir[X], rayp->r_dir[Y], rayp->r_dir[Z],
+ normvec[X], normvec[Y], normvec[Z]);
+ brst_log("\tDist %g Hit Pnt %g, %g, %g\n",
+ pp->pt_outhit->hit_dist,
+ pp->pt_outhit->hit_point[X],
+ pp->pt_outhit->hit_point[Y],
+ pp->pt_outhit->hit_point[Z]);
+ brst_log("\t%d of %d normals flipped.\n", flipct, totalct);
+#endif
+ VSCALE(normvec, normvec, -1.0);
+ ret = 0;
+ }
+ return ret;
+}
+
+
+/*
+ int f_ShotMiss(struct application *ap)
+
+ Shot missed the model; if ground bursting is enabled, intersect with
+ ground plane, else just arrange for appropriate background color for
+ debugging.
+*/
+static int
+f_ShotMiss(struct application *ap)
+{
+ if (groundburst) {
+ fastf_t dist;
+ fastf_t hitpoint[3];
+ /* first find intersection of shot with ground plane */
+ if (ap->a_ray.r_dir[Z] >= 0.0)
+ /* Shot direction is upward, can't hit the ground
+ from underneath. */
+ goto missed_ground;
+ if (ap->a_ray.r_pt[Z] <= -grndht)
+ /* Must be above ground to hit it from above. */
+ goto missed_ground;
+ /* ground plane is grndht distance below the target origin */
+ hitpoint[Z] = -grndht;
+ /* distance along ray from ray origin to ground plane */
+ dist = (hitpoint[Z] - ap->a_ray.r_pt[Z]) / ap->a_ray.r_dir[Z];
+ /* solve for X and Y intersection coordinates */
+ hitpoint[X] = ap->a_ray.r_pt[X] + ap->a_ray.r_dir[X]*dist;
+ hitpoint[Y] = ap->a_ray.r_pt[Y] + ap->a_ray.r_dir[Y]*dist;
+ /* check for limits of ground plane */
+ if (hitpoint[X] <= grndfr && hitpoint[X] >= -grndbk
+ && hitpoint[Y] <= grndlf && hitpoint[Y] >= -grndrt
+ ) {
+ /* We have a hit. */
+ if (fbfile[0] != NUL)
+ paintCellFb(ap, pixghit,
+ zoom == 1 ? pixblack : pixbkgr);
+ if (bdist > 0.0) {
+ /* simulate standoff fuzing */
+ VJOIN1(hitpoint, hitpoint, -bdist,
+ ap->a_ray.r_dir);
+ } else
+ if (bdist < 0.0) {
+ /* interior burst not implemented in ground */
+ brst_log("User error: %s %s.\n",
+ "negative burst distance can not be",
+ "specified with ground plane bursting"
+ );
+ fatalerror = 1;
+ return -1;
+ }
+ /* else bdist == 0.0, no adjustment necessary */
+ /* only burst if nspallrays greater than zero */
+ if (nspallrays > 0) {
+ prntBurstHdr(hitpoint, viewdir);
+ return burstPoint(ap, zaxis, hitpoint);
+ } else
+ return 1;
+ }
+ }
+missed_ground :
+ if (fbfile[0] != NUL)
+ paintCellFb(ap, pixmiss, zoom == 1 ? pixblack : pixbkgr);
+ VSETALL(ap->a_color, 0.0); /* All misses black. */
+ return 0;
+}
+
+
+/*
+ int f_BurstMiss(struct application *ap)
+
+ Burst ray missed the model, so do nothing.
+*/
+static int
+f_BurstMiss(struct application *ap)
+{
+ VSETALL(ap->a_color, 0.0); /* All misses black. */
+ return 0;
+}
+
+
+/*
+ int getRayOrigin(struct application *ap)
+
+ This routine fills in the ray origin ap->a_ray.r_pt by folding
+ together firing mode and dithering options. By-products of this
+ routine include the grid offsets which are stored in ap->a_uvec,
+ 2-digit random numbers (when opted) which are stored in ap->a_user,
+ and grid indices are stored in ap->a_x and ap->a_y. Return
+ codes are: 0 for failure to read new firing coordinates, or
+ 1 for success.
+*/
+static int
+getRayOrigin(struct burst_state *s, struct application *ap)
+{
+ fastf_t *vec = ap->a_uvec;
+ fastf_t gridyinc[3], gridxinc[3];
+ fastf_t scalecx, scalecy;
+ if (TSTBIT(firemode, FM_SHOT)) {
+ if (TSTBIT(firemode, FM_FILE)) {
+ switch (readShot(vec)) {
+ case EOF : return EOF;
+ case 1 : break;
+ case 0 : return 0;
+ }
+ } else /* Single shot specified. */
+ VMOVE(vec, fire);
+ if (TSTBIT(firemode, FM_3DIM)) {
+ fastf_t hitpoint[3];
+ /* Project 3-d hit-point back into grid space. */
+ VMOVE(hitpoint, vec);
+ vec[X] = VDOT(gridhor, hitpoint);
+ vec[Y] = VDOT(gridver, hitpoint);
+ }
+ ap->a_x = vec[X] / cellsz;
+ ap->a_y = vec[Y] / cellsz;
+ scalecx = vec[X];
+ scalecy = vec[Y];
+ } else {
+ fastf_t xoffset = 0.0;
+ fastf_t yoffset = 0.0;
+ ap->a_x = currshot % gridwidth + gridxorg;
+ ap->a_y = currshot / gridwidth + gridyorg;
+ if (dithercells) {
+ /* 2-digit random number, 1's place gives X
+ offset, 10's place gives Y offset.
+ */
+ ap->a_user = lrint(bn_randmt() * 100.0) % 100;
+ xoffset = (ap->a_user%10)*0.1 - 0.5;
+ yoffset = (ap->a_user/10)*0.1 - 0.5;
+ }
+ /* Compute magnitude of grid offsets. */
+ scalecx = (fastf_t) ap->a_x + xoffset;
+ scalecy = (fastf_t) ap->a_y + yoffset;
+ vec[X] = scalecx *= cellsz;
+ vec[Y] = scalecy *= cellsz;
+ }
+ /* Compute cell horizontal and vertical vectors relative to
+ grid origin. */
+ VSCALE(gridxinc, gridhor, scalecx);
+ VSCALE(gridyinc, gridver, scalecy);
+ VADD2(ap->a_ray.r_pt, gridsoff, gridyinc);
+ VADD2(ap->a_ray.r_pt, ap->a_ray.r_pt, gridxinc);
+ return 1;
+}
+
+
+/*
+ Construct a direction vector out of azimuth and elevation angles
+ in radians, allocating storage for it and returning its address.
+*/
+static void
+consVector(fastf_t *vec, fastf_t azim, fastf_t elev)
+{
+ /* Store cosine of the elevation to save calculating twice. */
+ fastf_t cosE;
+ cosE = cos(elev);
+ vec[0] = cos(azim) * cosE;
+ vec[1] = sin(azim) * cosE;
+ vec[2] = sin(elev);
+ return;
+}
+
+
+
+
+
+static void
+view_end(struct burst_state *s)
+{
+ if (gridfile[0] != NUL)
+ (void) fflush(s->gridfp);
+ if (histfile[0] != NUL)
+ (void) fflush(s->histfp);
+ if (plotfile[0] != NUL)
+ (void) fflush(s->plotfp);
+ if (outfile[0] != NUL)
+ (void) fflush(s->outfp);
+ if (shotlnfile[0] != NUL)
+ (void) fflush(s->shotlnfp);
+ prntTimer("view");
+ if (s->noverlaps > 0) {
+ bu_log("%d overlaps detected over %g mm thick.\n", s->noverlaps,
OVERLAP_TOL);
+ }
+ return;
+}
+
+/*
+ void lgtModel(struct application *ap, struct partition *pp,
+ struct hit *hitp, struct xray *rayp,
+ fastf_t surfnorm[3])
+
+ This routine is a simple lighting model which places RGB coefficients
+ (0 to 1) in ap->a_color based on the cosine of the angle between
+ the surface normal and viewing direction and the color associated with
+ the component. Also, the distance to the surface is placed in
+ ap->a_cumlen so that the impact location can be projected into grid
+ space.
+*/
+static void
+lgtModel(struct application *ap, struct partition *pp, struct hit *hitp,
struct xray *UNUSED(rayp), fastf_t surfnorm[3])
+{
+ struct colors *colorp;
+ fastf_t intensity = -VDOT(viewdir, surfnorm);
+ if (intensity < 0.0)
+ intensity = -intensity;
+
+ colorp = findColors(pp->pt_regionp->reg_regionid, &s->colorids
+ if (colorp != COLORS_NULL) {
+ ap->a_color[RED] = (fastf_t)colorp->c_rgb[RED]/255.0;
+ ap->a_color[GRN] = (fastf_t)colorp->c_rgb[GRN]/255.0;
+ ap->a_color[BLU] = (fastf_t)colorp->c_rgb[BLU]/255.0;
+ } else {
+ ap->a_color[RED] = ap->a_color[GRN] = ap->a_color[BLU] = 1.0;
+ }
+ VSCALE(ap->a_color, ap->a_color, intensity);
+ ap->a_cumlen = hitp->hit_dist;
+}
+
+
+/*
+ int readBurst(fastf_t *vec)
+
+ This routine reads the next set of burst point coordinates from the
+ input stream burstfp. Returns 1 for success, 0 for a format
+ error and EOF for normal end-of-file. If 0 is returned,
+ fatalerror will be set to 1.
+*/
+static int
+readBurst(struct burst_state *s, fastf_t *vec)
+{
+ int items;
+ double scan[3];
+
+ assert(burstfp != (FILE *) NULL);
+ /* read 3D firing coordinates from input stream */
+ items = fscanf(burstfp, "%lf %lf %lf", &scan[0], &scan[1], &scan[2]);
+ VMOVE(vec, scan); /* double to fastf_t */
+ if (items != 3) {
+ if (items != EOF) {
+ brst_log("Fatal error: %d burst coordinates read.\n",
+ items);
+ fatalerror = 1;
+ return 0;
+ } else {
+ return EOF;
+ }
+ } else {
+ vec[X] /= unitconv;
+ vec[Y] /= unitconv;
+ vec[Z] /= unitconv;
+ }
+ return 1;
+}
+
+
+/*
+ int readShot(fastf_t *vec)
+
+ This routine reads the next set of firing coordinates from the
+ input stream shotfp, using the format selected by the firemode
+ bitflag. Returns 1 for success, 0 for a format error and EOF
+ for normal end-of-file. If 0 is returned, fatalerror will be
+ set to 1.
+*/
+static int
+readShot(struct burst_state *s, fastf_t *vec)
+{
+ double scan[3] = VINIT_ZERO;
+
+ assert(shotfp != (FILE *) NULL);
+
+ if (! TSTBIT(firemode, FM_3DIM)) {
+ /* absence of 3D flag means 2D */
+ int items;
+
+ /* read 2D firing coordinates from input stream */
+ items = fscanf(shotfp, "%lf %lf", &scan[0], &scan[1]);
+ VMOVE(vec, scan);
+ if (items != 2) {
+ if (items != EOF) {
+ brst_log("Fatal error: only %d firing coordinates read.\n",
items);
+ fatalerror = 1;
+ return 0;
+ } else {
+ return EOF;
+ }
+ } else {
+ vec[X] /= unitconv;
+ vec[Y] /= unitconv;
+ }
+ } else
+ if (TSTBIT(firemode, FM_3DIM)) {
+ /* 3D coordinates */
+ int items;
+
+ /* read 3D firing coordinates from input stream */
+ items = fscanf(shotfp, "%lf %lf %lf", &scan[0], &scan[1], &scan[2]);
+ VMOVE(vec, scan); /* double to fastf_t */
+ if (items != 3) {
+ if (items != EOF) {
+ brst_log("Fatal error: %d firing coordinates read.\n",
items);
+ fatalerror = 1;
+ return 0;
+ } else {
+ return EOF;
+ }
+ } else {
+ vec[X] /= unitconv;
+ vec[Y] /= unitconv;
+ vec[Z] /= unitconv;
+ }
+ } else {
+ brst_log("BUG: readShot called with bad firemode.\n");
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ int roundToInt(fastf_t f)
+
+ RETURN CODES: the nearest integer to f.
+*/
+int roundToInt(fastf_t f)
+{
+ int a;
+ a = f;
+ if (f - a >= 0.5)
+ return a + 1;
+ else
+ return a;
+}
+
+
+static void
+spallVec(fastf_t *dvec, fastf_t *s_rdir, fastf_t phi, fastf_t gammaval)
+{
+ fastf_t cosphi = cos(phi);
+ fastf_t singamma = sin(gammaval);
+ fastf_t cosgamma = cos(gammaval);
+ fastf_t csgaphi, ssgaphi;
+ fastf_t sinphi = sin(phi);
+ fastf_t cosdphi[3];
+ fastf_t fvec[3];
+ fastf_t evec[3];
+
+ if (VNEAR_EQUAL(dvec, zaxis, VEC_TOL)
+ || VNEAR_EQUAL(dvec, negzaxis, VEC_TOL)
+ ) {
+ VMOVE(evec, xaxis);
+ } else {
+ VCROSS(evec, dvec, zaxis);
+ }
+ VCROSS(fvec, evec, dvec);
+ VSCALE(cosdphi, dvec, cosphi);
+ ssgaphi = singamma * sinphi;
+ csgaphi = cosgamma * sinphi;
+ VJOIN2(s_rdir, cosdphi, ssgaphi, evec, csgaphi, fvec);
+ VUNITIZE(s_rdir);
+ return;
+}
+
+
+static int
+burstRay(struct burst_state *s)
+{
+ /* Need local copy of all but readonly variables for concurrent
+ threads of execution. */
+ struct application a_spall;
+ fastf_t phi;
+ int hitcrit = 0;
+ a_spall = a_burst;
+ a_spall.a_resource = RESOURCE_NULL;
+ for (; ! userinterrupt;) {
+ fastf_t sinphi;
+ fastf_t gammaval, gammainc, gammalast;
+ int done;
+ int m;
+ bu_semaphore_acquire(RT_SEM_WORKER);
+ phi = comphi;
+ comphi += phiinc;
+ done = phi > conehfangle;
+ bu_semaphore_release(RT_SEM_WORKER);
+ if (done)
+ break;
+ sinphi = sin(phi);
+ sinphi = fabs(sinphi);
+ m = (M_2PI * sinphi)/delta + 1;
+ gammainc = M_2PI / m;
+ gammalast = M_2PI - gammainc + VUNITIZE_TOL;
+ for (gammaval = 0.0; gammaval <= gammalast; gammaval += gammainc) {
+ int ncrit;
+ spallVec(a_burst.a_ray.r_dir, a_spall.a_ray.r_dir,
+ phi, gammaval);
+
+ if (plotline)
+ plotRayPoint(&a_spall.a_ray);
+ else
+ plotRayLine(&a_spall.a_ray);
+
+ bu_semaphore_acquire(RT_SEM_WORKER);
+ a_spall.a_user = a_burst.a_user++;
+ bu_semaphore_release(RT_SEM_WORKER);
+ if ((ncrit = rt_shootray(&a_spall)) == -1
+ && fatalerror) {
+ /* Fatal error in application routine. */
+ brst_log("Error: ray tracing aborted.\n");
+ return 0;
+ }
+ if (fbfile[0] != NUL && ncrit > 0) {
+ paintSpallFb(&a_spall);
+ hitcrit = 1;
+ }
+ if (histfile[0] != NUL) {
+ bu_semaphore_acquire(BU_SEM_SYSCALL);
+ (void) fprintf(histfp, "%d\n", ncrit);
+ bu_semaphore_release(BU_SEM_SYSCALL);
+ }
+ }
+ }
+ if (fbfile[0] != NUL) {
+ if (hitcrit)
+ paintCellFb(&a_spall, pixcrit, pixtarg);
+ else
+ paintCellFb(&a_spall, pixbhit, pixtarg);
+ }
+ return 1;
+}
+
+
+
+/* To facilitate one-time per burst point initialization of the spall
+ ray application structure while leaving burstRay() with the
+ capability of being used as a multitasking process, a_burst must
+ be accessible by both the burstPoint() and burstRay() routines, but
+ can be local to this module. */
+static struct application a_burst; /* prototype spall ray */
+
+/*
+ * This routine dispatches the burst point ray tracing task burstRay().
+ * RETURN CODES: 0 for fatal ray tracing error, 1 otherwise.
+ *
+ * bpt is burst point coordinates.
+ */
+static int
+burstPoint(struct application *ap, fastf_t *normal, fastf_t *bpt)
+{
+ a_burst = *ap;
+ a_burst.a_miss = f_BurstMiss;
+ a_burst.a_hit = f_BurstHit;
+ a_burst.a_level++;
+ a_burst.a_user = 0; /* ray number */
+ a_burst.a_purpose = "spall ray";
+ assert(a_burst.a_overlap == ap->a_overlap);
+
+ /* If pitch or yaw is specified, cant the main penetrator
+ axis. */
+ if (cantwarhead) {
+ VADD2(a_burst.a_ray.r_dir, a_burst.a_ray.r_dir, cantdelta);
+ VUNITIZE(a_burst.a_ray.r_dir);
+ }
+ /* If a deflected cone is specified (the default) the spall cone
+ axis is half way between the main penetrator axis and exit
+ normal of the spalling component.
+ */
+ if (deflectcone) {
+ VADD2(a_burst.a_ray.r_dir, a_burst.a_ray.r_dir, normal);
+ VUNITIZE(a_burst.a_ray.r_dir);
+ }
+ VMOVE(a_burst.a_ray.r_pt, bpt);
+
+ comphi = 0.0; /* Initialize global for concurrent access. */
+
+ /* SERIAL case -- one CPU does all the work. */
+ return burstRay();
+}
+
+/*
+ This routine gets called when explicit burst points are being
+ input. Crank through all burst points. Return code of 0
+ would indicate a failure in the application routine given to
+ rt_shootray() or an error or EOF in getting the next set of
+ burst point coordinates.
+*/
+static int
+doBursts(struct burst_state *s)
+{
+ int status = 1;
+ noverlaps = 0;
+ VMOVE(ag.a_ray.r_dir, viewdir);
+
+ for (; ! userinterrupt; view_pix(&ag)) {
+ if (TSTBIT(firemode, FM_FILE)
+ && (!(status = readBurst(burstpoint)) || status == EOF)
+ )
+ break;
+ ag.a_level = 0; /* initialize recursion level */
+ plotGrid(burstpoint);
+
+ prntBurstHdr(burstpoint, viewdir);
+ if (! burstPoint(&ag, zaxis, burstpoint)) {
+ /* fatal error in application routine */
+ brst_log("Fatal error: raytracing aborted.\n");
+ return 0;
+ }
+ if (! TSTBIT(firemode, FM_FILE)) {
+ view_pix(&ag);
+ break;
+ }
+ }
+ return status == EOF ? 1 : status;
+}
+
+/*
+ int gridShot(void)
+
+ This routine is the grid-level raytracing task; suitable for a
+ multi-tasking process. Return code of 0 would indicate a
+ failure in the application routine given to rt_shootray() or an
+ error or EOF in getting the next set of firing coordinates.
+*/
+static int
+gridShot(struct burst_state *s)
+{
+ int status = 1;
+ struct application a;
+ a = ag;
+ a.a_resource = RESOURCE_NULL;
+
+ assert(a.a_hit == ag.a_hit);
+ assert(a.a_miss == ag.a_miss);
+ assert(a.a_overlap == ag.a_overlap);
+ assert(a.a_rt_i == ag.a_rt_i);
+ assert(a.a_onehit == ag.a_onehit);
+ a.a_user = 0;
+ a.a_purpose = "shotline";
+ prntGridOffsets(gridxorg, gridyorg);
+ noverlaps = 0;
+ for (; ! userinterrupt; view_pix(&a)) {
+ if (! TSTBIT(firemode, FM_SHOT) && currshot > lastshot)
+ break;
+ if (! (status = getRayOrigin(&a)) || status == EOF)
+ break;
+ currshot++;
+ prntFiringCoords(a.a_uvec);
+ VMOVE(a.a_ray.r_dir, viewdir);
+ a.a_level = 0; /* initialize recursion level */
+ plotGrid(a.a_ray.r_pt);
+ if (rt_shootray(&a) == -1 && fatalerror) {
+ /* fatal error in application routine */
+ brst_log("Fatal error: raytracing aborted.\n");
+ return 0;
+ }
+ if (! TSTBIT(firemode, FM_FILE) && TSTBIT(firemode, FM_SHOT)) {
+ view_pix(&a);
+ break;
+ }
+ }
+ return status == EOF ? 1 : status;
+}
+
+/*
+ This routine dispatches the top-level ray tracing task.
+*/
+void
+gridModel(struct burst_state *s)
+{
+ ag.a_onehit = 0;
+ ag.a_overlap = reportoverlaps ? f_Overlap : f_HushOverlap;
+ ag.a_logoverlap = rt_silent_logoverlap;
+ ag.a_rt_i = rtip;
+ if (! TSTBIT(firemode, FM_BURST)) {
+ /* set up for shotlines */
+ ag.a_hit = f_ShotHit;
+ ag.a_miss = f_ShotMiss;
+ }
+
+ plotInit(); /* initialize plot file if appropriate */
+
+ if (! imageInit()) {
+ /* initialize frame buffer if appropriate */
+ warning("Error: problem opening frame buffer.");
+ return;
+ }
+ /* output initial line for this aspect */
+ prntAspectInit();
+
+ fatalerror = 0;
+ userinterrupt = 0; /* set by interrupt handler */
+
+ rt_prep_timer();
+ notify("Raytracing", NOTIFY_ERASE);
+
+ if (TSTBIT(firemode, FM_BURST)) {
+ if (! doBursts())
+ return;
+ else
+ goto endvu;
+ }
+
+ /* get starting and ending shot number */
+ currshot = 0;
+ lastshot = gridwidth * gridheight - 1;
+
+ /* SERIAL case -- one CPU does all the work */
+ if (! gridShot())
+ return;
+endvu: view_end();
+ return;
+}
+
+/*
+ Grid initialization routine; must be done once per view.
+*/
+void
+gridInit(struct burst_state *s)
+{
+ notify("Initializing grid", NOTIFY_APPEND);
+ rt_prep_timer();
+
+#if DEBUG_SHOT
+ if (TSTBIT(firemode, FM_BURST))
+ brst_log("gridInit: reading burst points.\n");
+ else {
+ if (TSTBIT(firemode, FM_SHOT))
+ brst_log("gridInit: shooting discrete shots.\n");
+ else
+ brst_log("gridInit: shooting %s.\n",
+ TSTBIT(firemode, FM_PART) ?
+ "partial envelope" : "full envelope");
+ }
+ if (TSTBIT(firemode, FM_BURST) || TSTBIT(firemode, FM_SHOT)) {
+ brst_log("gridInit: reading %s coordinates from %s.\n",
+ TSTBIT(firemode, FM_3DIM) ? "3-d" : "2-d",
+ TSTBIT(firemode, FM_FILE) ? "file" : "command stream");
+
+ } else
+ if (TSTBIT(firemode, FM_FILE) || TSTBIT(firemode, FM_3DIM))
+ brst_log("BUG: insane combination of fire mode bits:0x%x\n",
+ firemode);
+ if (TSTBIT(firemode, FM_BURST) || shotburst)
+ nriplevels = 1;
+ else
+ nriplevels = 0;
+ if (!shotburst && groundburst) {
+ (void) snprintf(scrbuf, LNBUFSZ,
+ "Ground bursting directive ignored: %s.\n",
+ "only relevant if bursting along shotline");
+ warning(scrbuf);
+ brst_log(scrbuf);
+ }
+#endif
+ /* compute grid unit vectors */
+ gridRotate(viewazim, viewelev, 0.0, gridhor, gridver);
+
+ if (!NEAR_ZERO(yaw, VDIVIDE_TOL) || !NEAR_ZERO(pitch, VDIVIDE_TOL)) {
+ fastf_t negsinyaw = -sin(yaw);
+ fastf_t sinpitch = sin(pitch);
+ fastf_t xdeltavec[3], ydeltavec[3];
+#if DEBUG_SHOT
+ brst_log("gridInit: canting warhead\n");
+#endif
+ cantwarhead = 1;
+ VSCALE(xdeltavec, gridhor, negsinyaw);
+ VSCALE(ydeltavec, gridver, sinpitch);
+ VADD2(cantdelta, xdeltavec, ydeltavec);
+ }
+
+ /* unit vector from origin of model toward eye */
+ consVector(viewdir, viewazim, viewelev);
+
+ /* reposition file pointers if necessary */
+ if (TSTBIT(firemode, FM_SHOT) && TSTBIT(firemode, FM_FILE))
+ rewind(shotfp);
+ else
+ if (TSTBIT(firemode, FM_BURST) && TSTBIT(firemode, FM_FILE))
+ rewind(burstfp);
+
+ /* Compute distances from grid origin (model origin) to each
+ border of grid, and grid indices at borders of grid.
+ */
+ if (! TSTBIT(firemode, FM_PART)) {
+ fastf_t modelmin[3];
+ fastf_t modelmax[3];
+ if (groundburst) {
+ /* extend grid to include ground platform */
+ modelmax[X] = FMAX(rtip->mdl_max[X], grndfr);
+ modelmin[X] = FMIN(rtip->mdl_min[X], -grndbk);
+ modelmax[Y] = FMAX(rtip->mdl_max[Y], grndlf);
+ modelmin[Y] = FMIN(rtip->mdl_min[Y], -grndrt);
+ modelmax[Z] = rtip->mdl_max[Z];
+ modelmin[Z] = FMIN(rtip->mdl_min[Z], -grndht);
+ } else {
+ /* size grid by model RPP */
+ VMOVE(modelmin, rtip->mdl_min);
+ VMOVE(modelmax, rtip->mdl_max);
+ }
+ /* Calculate extent of grid. */
+ gridrt = FMAX(gridhor[X] * modelmax[X],
+ gridhor[X] * modelmin[X]
+ ) +
+ FMAX(gridhor[Y] * modelmax[Y],
+ gridhor[Y] * modelmin[Y]
+ ) +
+ FMAX(gridhor[Z] * modelmax[Z],
+ gridhor[Z] * modelmin[Z]
+ );
+ gridlf = FMIN(gridhor[X] * modelmax[X],
+ gridhor[X] * modelmin[X]
+ ) +
+ FMIN(gridhor[Y] * modelmax[Y],
+ gridhor[Y] * modelmin[Y]
+ ) +
+ FMIN(gridhor[Z] * modelmax[Z],
+ gridhor[Z] * modelmin[Z]
+ );
+ gridup = FMAX(gridver[X] * modelmax[X],
+ gridver[X] * modelmin[X]
+ ) +
+ FMAX(gridver[Y] * modelmax[Y],
+ gridver[Y] * modelmin[Y]
+ ) +
+ FMAX(gridver[Z] * modelmax[Z],
+ gridver[Z] * modelmin[Z]
+ );
+ griddn = FMIN(gridver[X] * modelmax[X],
+ gridver[X] * modelmin[X]
+ ) +
+ FMIN(gridver[Y] * modelmax[Y],
+ gridver[Y] * modelmin[Y]
+ ) +
+ FMIN(gridver[Z] * modelmax[Z],
+ gridver[Z] * modelmin[Z]
+ );
+ /* Calculate extent of model in plane of grid. */
+ if (groundburst) {
+ modlrt = FMAX(gridhor[X] * rtip->mdl_max[X],
+ gridhor[X] * rtip->mdl_min[X]
+ ) +
+ FMAX(gridhor[Y] * rtip->mdl_max[Y],
+ gridhor[Y] * rtip->mdl_min[Y]
+ ) +
+ FMAX(gridhor[Z] * rtip->mdl_max[Z],
+ gridhor[Z] * rtip->mdl_min[Z]
+ );
+ modllf = FMIN(gridhor[X] * rtip->mdl_max[X],
+ gridhor[X] * rtip->mdl_min[X]
+ ) +
+ FMIN(gridhor[Y] * rtip->mdl_max[Y],
+ gridhor[Y] * rtip->mdl_min[Y]
+ ) +
+ FMIN(gridhor[Z] * rtip->mdl_max[Z],
+ gridhor[Z] * rtip->mdl_min[Z]
+ );
+ modlup = FMAX(gridver[X] * rtip->mdl_max[X],
+ gridver[X] * rtip->mdl_min[X]
+ ) +
+ FMAX(gridver[Y] * rtip->mdl_max[Y],
+ gridver[Y] * rtip->mdl_min[Y]
+ ) +
+ FMAX(gridver[Z] * rtip->mdl_max[Z],
+ gridver[Z] * rtip->mdl_min[Z]
+ );
+ modldn = FMIN(gridver[X] * rtip->mdl_max[X],
+ gridver[X] * rtip->mdl_min[X]
+ ) +
+ FMIN(gridver[Y] * rtip->mdl_max[Y],
+ gridver[Y] * rtip->mdl_min[Y]
+ ) +
+ FMIN(gridver[Z] * rtip->mdl_max[Z],
+ gridver[Z] * rtip->mdl_min[Z]
+ );
+ } else {
+ modlrt = gridrt;
+ modllf = gridlf;
+ modlup = gridup;
+ modldn = griddn;
+ }
+ }
+ gridxorg = gridlf / cellsz;
+ gridxfin = gridrt / cellsz;
+ gridyorg = griddn / cellsz;
+ gridyfin = gridup / cellsz;
+
+ /* allow for randomization of cells */
+ if (dithercells) {
+ gridxorg--;
+ gridxfin++;
+ gridyorg--;
+ gridyfin++;
+ }
+#if DEBUG_SHOT
+ brst_log("gridInit: xorg, xfin, yorg, yfin=%d, %d, %d, %d\n",
+ gridxorg, gridxfin, gridyorg, gridyfin);
+ brst_log("gridInit: left, right, down, up=%g, %g, %g, %g\n",
+ gridlf, gridrt, griddn, gridup);
+#endif
+
+ /* compute stand-off distance */
+ standoff = FMAX(viewdir[X] * rtip->mdl_max[X],
+ viewdir[X] * rtip->mdl_min[X]
+ ) +
+ FMAX(viewdir[Y] * rtip->mdl_max[Y],
+ viewdir[Y] * rtip->mdl_min[Y]
+ ) +
+ FMAX(viewdir[Z] * rtip->mdl_max[Z],
+ viewdir[Z] * rtip->mdl_min[Z]
+ );
+
+ /* determine largest grid dimension for frame buffer display */
+ gridwidth = gridxfin - gridxorg + 1;
+ gridheight = gridyfin - gridyorg + 1;
+ gridsz = FMAX(gridwidth, gridheight);
+
+ /* vector to grid origin from model origin */
+ VSCALE(gridsoff, viewdir, standoff);
+
+ /* direction of grid rays */
+ VSCALE(viewdir, viewdir, -1.0);
+
+ prntTimer("grid");
+ notify(NULL, NOTIFY_DELETE);
+ return;
+}
+
+/*
+ Burst grid initialization routine; should be called once per view.
+ Does some one-time computation for current bursting parameters; the
+ following globals are filled in:
+
+ delta -- the target ray delta angle
+ phiinc -- the actual angle between concentric rings
+ raysolidangle -- the average solid angle per spall ray
+
+ Determines actual number of sampling rays yielded by the even-
+ distribution algorithm from the number requested.
+*/
+void
+spallInit(struct burst_state *s)
+{
+ fastf_t theta; /* solid angle of spall sampling cone */
+ fastf_t phi; /* angle between ray and cone axis */
+ fastf_t philast; /* guard against floating point error */
+ int spallct = 0; /* actual no. of sampling rays */
+ int n;
+ if (nspallrays < 1) {
+ delta = 0.0;
+ phiinc = 0.0;
+ raysolidangle = 0.0;
+ brst_log("%d sampling rays\n", spallct);
+ return;
+ }
+
+ /* Compute sampling cone of rays which are equally spaced. */
+ theta = M_2PI * (1.0 - cos(conehfangle)); /* solid angle */
+ delta = sqrt(theta/nspallrays); /* angular ray delta */
+ n = conehfangle / delta;
+ phiinc = conehfangle / n;
+ philast = conehfangle + VUNITIZE_TOL;
+ /* Crank through spall cone generation once to count actual number
+ generated.
+ */
+ for (phi = 0.0; phi <= philast; phi += phiinc) {
+ fastf_t sinphi = sin(phi);
+ fastf_t gammaval, gammainc, gammalast;
+ int m;
+ sinphi = fabs(sinphi);
+ m = (M_2PI * sinphi)/delta + 1;
+ gammainc = M_2PI / m;
+ gammalast = M_2PI-gammainc + VUNITIZE_TOL;
+ for (gammaval = 0.0; gammaval <= gammalast; gammaval += gammainc)
+ spallct++;
+ }
+ raysolidangle = theta / spallct;
+ brst_log("Solid angle of sampling cone = %g\n", theta);
+ brst_log("Solid angle per sampling ray = %g\n", raysolidangle);
+ brst_log("%d sampling rays\n", spallct);
+ return;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */
Property changes on: brlcad/branches/bioh/src/burst2/grid.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits