int TSplit::split(const char *token, const char *buf) { _CHECK_RS(token,NULL,-1); _CHECK_RS(buf,NULL,-1); char *pos = NULL; char *buf_pt = NULL; int buf_len = strlen(buf) + 1; int token_len = strlen(token); if (m_nBufLen < buf_len) { if (m_strBuf) { FREE_PT(m_strBuf); } m_strBuf = (char *)calloc(buf_len, 1); _CHECK_RS(m_strBuf, NULL, -1); } else { memset(m_strBuf, 0, m_nBufLen); } m_nCnt = 0; memcpy(m_strBuf, buf, buf_len); buf_pt = m_strBuf; while (1) { if (0 == buf_pt[0]) { if (0 < m_nCnt) m_Array[m_nCnt++] = (PVOID)""; break; } if (CheckExtend()) return -1; pos = strstr(buf_pt, token); if (!pos) { m_Array[m_nCnt++] = buf_pt; break; } *pos = 0; if (pos != buf_pt) m_Array[m_nCnt++] = buf_pt; else m_Array[m_nCnt++] = (PVOID)""; buf_pt = pos + token_len; } return 0; }
void part_compact(register struct application *ap, register struct partition *PartHeadp, fastf_t tolerance) { fastf_t gap; struct partition *pp; struct partition *nextpp; /* first eliminate zero thickness partitions */ pp = PartHeadp->pt_forw; while ( pp != PartHeadp ) { fastf_t comp_thickness; nextpp = pp->pt_forw; comp_thickness = pp->pt_outhit->hit_dist - pp->pt_inhit->hit_dist; if ( comp_thickness <= 0.0 ) { DEQUEUE_PT( pp ); FREE_PT( pp, ap->a_resource); } pp = nextpp; } for (pp = PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw) { top: nextpp = pp->pt_forw; if (nextpp == PartHeadp) { break; } if ( pp->pt_regionp->reg_regionid > 0 && nextpp->pt_regionp->reg_regionid > 0 ) { if (pp->pt_regionp->reg_regionid != nextpp->pt_regionp->reg_regionid) { continue; } } else if ( pp->pt_regionp->reg_regionid <= 0 && nextpp->pt_regionp->reg_regionid <= 0 ) { if ( pp->pt_regionp->reg_aircode != nextpp->pt_regionp->reg_aircode ) { continue; } } else continue; gap = nextpp->pt_inhit->hit_dist - pp->pt_outhit->hit_dist; /* The following line is a diagnostic that is worth reusing: * bu_log("gap=%e\n", gap); */ if (gap > tolerance) { continue; } /* Eliminate the gap by collapsing the two partitions * into one. The below lines have been commented out but * should be retained for debugging purposes. */ #if 0 bu_log("part_comp: collapsing gap of %e mm between id=%d and id=%d air=%d and air=%d\n", gap, pp->pt_regionp->reg_regionid, nextpp->pt_regionp->reg_regionid, pp->pt_regionp->reg_aircode, nextpp->pt_regionp->reg_aircode); #endif pp->pt_outseg = nextpp->pt_outseg; pp->pt_outhit = nextpp->pt_outhit; pp->pt_outflip = nextpp->pt_outflip; /* * Dequeue and free the unwanted partition structure. * Referenced segments, etc, will be freed by rt_shootray(). */ DEQUEUE_PT(nextpp); FREE_PT(nextpp, ap->a_resource); goto top; } }
/** * Given a ray, shoot it at all the relevant parts of the model, * (building the HeadSeg chain), and then call rt_boolregions() to * build and evaluate the partition chain. If the ray actually hit * anything, call the application's a_hit() routine with a pointer to * the partition chain, otherwise, call the application's a_miss() * routine. * * It is important to note that rays extend infinitely only in the * positive direction. The ray is composed of all points P, where * * P = r_pt + K * r_dir * * for K ranging from 0 to +infinity. There is no looking backwards. * * It is also important to note that the direction vector r_dir must * have unit length; this is mandatory, and is not ordinarily checked, * in the name of efficiency. * * Input: Pointer to an application structure, with these mandatory fields: * a_ray.r_pt Starting point of ray to be fired * a_ray.r_dir UNIT VECTOR with direction to fire in (dir cosines) * a_hit Routine to call when something is hit * a_miss Routine to call when ray misses everything * * Calls user's a_miss() or a_hit() routine as appropriate. Passes * a_hit() routine list of partitions, with only hit_dist fields * valid. Normal computation deferred to user code, to avoid needless * computation here. * * Returns: whatever the application function returns (an int). * * NOTE: The application functions may call rt_shootray() recursively. * Thus, none of the local variables may be static. * * An open issue for execution in a PARALLEL environment is locking of * the statistics variables. */ int rt_vshootray(struct application *ap) { struct seg *HeadSeg; int ret; vect_t inv_dir; /* inverses of ap->a_ray.r_dir */ struct bu_bitv *solidbits; /* bits for all solids shot so far */ struct bu_ptbl *regionbits; /* bits for all involved regions */ char *status; struct partition InitialPart; /* Head of Initial Partitions */ struct partition FinalPart; /* Head of Final Partitions */ int nrays = 1; /* for now */ int vlen; int id; int i; struct soltab **ary_stp; /* array of pointers */ struct xray **ary_rp; /* array of pointers */ struct seg *ary_seg; /* array of structures */ struct rt_i *rtip; int done; #define BACKING_DIST (-2.0) /* mm to look behind start point */ rtip = ap->a_rt_i; RT_AP_CHECK(ap); if (!ap->a_resource) { ap->a_resource = &rt_uniresource; } RT_CK_RESOURCE(ap->a_resource); if (RT_G_DEBUG&(DEBUG_ALLRAYS|DEBUG_SHOOT|DEBUG_PARTITION)) { bu_log("\n**********mshootray cpu=%d %d, %d lvl=%d (%s)\n", ap->a_resource->re_cpu, ap->a_x, ap->a_y, ap->a_level, ap->a_purpose != (char *)0 ? ap->a_purpose : "?"); VPRINT("Pnt", ap->a_ray.r_pt); VPRINT("Dir", ap->a_ray.r_dir); } rtip->rti_nrays++; if (rtip->needprep) rt_prep(rtip); /* Allocate dynamic memory */ vlen = nrays * rtip->rti_maxsol_by_type; ary_stp = (struct soltab **)bu_calloc(vlen, sizeof(struct soltab *), "*ary_stp[]"); ary_rp = (struct xray **)bu_calloc(vlen, sizeof(struct xray *), "*ary_rp[]"); ary_seg = (struct seg *)bu_calloc(vlen, sizeof(struct seg), "ary_seg[]"); /**** for each ray, do this ****/ InitialPart.pt_forw = InitialPart.pt_back = &InitialPart; FinalPart.pt_forw = FinalPart.pt_back = &FinalPart; HeadSeg = RT_SEG_NULL; solidbits = rt_get_solidbitv(rtip->nsolids, ap->a_resource); if (BU_LIST_IS_EMPTY(&ap->a_resource->re_region_ptbl)) { BU_ALLOC(regionbits, struct bu_ptbl); bu_ptbl_init(regionbits, 7, "rt_shootray() regionbits ptbl"); } else { regionbits = BU_LIST_FIRST(bu_ptbl, &ap->a_resource->re_region_ptbl); BU_LIST_DEQUEUE(®ionbits->l); BU_CK_PTBL(regionbits); } /* Compute the inverse of the direction cosines */ if (!ZERO(ap->a_ray.r_dir[X])) { inv_dir[X]=1.0/ap->a_ray.r_dir[X]; } else { inv_dir[X] = INFINITY; ap->a_ray.r_dir[X] = 0.0; } if (!ZERO(ap->a_ray.r_dir[Y])) { inv_dir[Y]=1.0/ap->a_ray.r_dir[Y]; } else { inv_dir[Y] = INFINITY; ap->a_ray.r_dir[Y] = 0.0; } if (!ZERO(ap->a_ray.r_dir[Z])) { inv_dir[Z]=1.0/ap->a_ray.r_dir[Z]; } else { inv_dir[Z] = INFINITY; ap->a_ray.r_dir[Z] = 0.0; } /* * XXX handle infinite solids here, later. */ /* * If ray does not enter the model RPP, skip on. * If ray ends exactly at the model RPP, trace it. */ if (!rt_in_rpp(&ap->a_ray, inv_dir, rtip->mdl_min, rtip->mdl_max) || ap->a_ray.r_max < 0.0) { rtip->nmiss_model++; if (ap->a_miss) ret = ap->a_miss(ap); else ret = 0; status = "MISS model"; goto out; } /* For each type of solid to be shot at, assemble the vectors */ for (id = 1; id <= ID_MAX_SOLID; id++) { register int nsol; if ((nsol = rtip->rti_nsol_by_type[id]) <= 0) continue; /* For each instance of this solid type */ for (i = nsol-1; i >= 0; i--) { ary_stp[i] = rtip->rti_sol_by_type[id][i]; ary_rp[i] = &(ap->a_ray); /* XXX, sb [ray] */ ary_seg[i].seg_stp = SOLTAB_NULL; BU_LIST_INIT(&ary_seg[i].l); } /* bounding box check */ /* bit vector per ray check */ /* mark elements to be skipped with ary_stp[] = SOLTAB_NULL */ ap->a_rt_i->nshots += nsol; /* later: skipped ones */ if (OBJ[id].ft_vshot) { OBJ[id].ft_vshot(ary_stp, ary_rp, ary_seg, nsol, ap); } else { vshot_stub(ary_stp, ary_rp, ary_seg, nsol, ap); } /* set bits for all solids shot at for each ray */ /* append resulting seg list to input for boolweave */ for (i = nsol-1; i >= 0; i--) { register struct seg *seg2; if (ary_seg[i].seg_stp == SOLTAB_NULL) { /* MISS */ ap->a_rt_i->nmiss++; continue; } ap->a_rt_i->nhits++; /* For now, do it the slow way. sb [ray] */ /* MUST dup it -- all segs have to live till after a_hit() */ RT_GET_SEG(seg2, ap->a_resource); *seg2 = ary_seg[i]; /* struct copy */ /* rt_boolweave(seg2, &InitialPart, ap); */ bu_bomb("FIXME: need to call boolweave here"); /* Add seg chain to list of used segs awaiting reclaim */ #if 0 /* FIXME: need to use waiting_segs/finished_segs here in * conjunction with rt_boolweave() { register struct seg *seg3 = seg2; while (seg3->seg_next != RT_SEG_NULL) seg3 = seg3->seg_next; seg3->seg_next = HeadSeg; HeadSeg = seg2; } */ #endif } } /* * Ray has finally left known space. */ if (InitialPart.pt_forw == &InitialPart) { if (ap->a_miss) ret = ap->a_miss(ap); else ret = 0; status = "MISSed all primitives"; goto freeup; } /* * All intersections of the ray with the model have been computed. * Evaluate the boolean trees over each partition. */ done = rt_boolfinal(&InitialPart, &FinalPart, BACKING_DIST, INFINITY, regionbits, ap, solidbits); if (done > 0) goto hitit; if (FinalPart.pt_forw == &FinalPart) { if (ap->a_miss) ret = ap->a_miss(ap); else ret = 0; status = "MISS bool"; goto freeup; } /* * Ray/model intersections exist. Pass the list to the user's * a_hit() routine. Note that only the hit_dist elements of * pt_inhit and pt_outhit have been computed yet. To compute both * hit_point and hit_normal, use the * * RT_HIT_NORMAL(NULL, hitp, stp, rayp, 0); * * macro. To compute just hit_point, use * * VJOIN1(hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir); */ hitit: if (RT_G_DEBUG&DEBUG_SHOOT) rt_pr_partitions(rtip, &FinalPart, "a_hit()"); if (ap->a_hit) ret = ap->a_hit(ap, &FinalPart, HeadSeg/* &finished_segs */); else ret = 0; status = "HIT"; /* * Processing of this ray is complete. Free dynamic resources. */ freeup: { register struct partition *pp; /* Free up initial partition list */ for (pp = InitialPart.pt_forw; pp != &InitialPart;) { register struct partition *newpp; newpp = pp; pp = pp->pt_forw; FREE_PT(newpp, ap->a_resource); } /* Free up final partition list */ for (pp = FinalPart.pt_forw; pp != &FinalPart;) { register struct partition *newpp; newpp = pp; pp = pp->pt_forw; FREE_PT(newpp, ap->a_resource); } } /* Segs can't be freed until after a_hit() has returned */ #if 0 /* FIXME: depends on commented out code above */ if (HeadSeg) RT_FREE_SEG_LIST(HeadSeg, ap->a_resource); #endif out: bu_free((char *)ary_stp, "*ary_stp[]"); bu_free((char *)ary_rp, "*ary_rp[]"); bu_free((char *)ary_seg, "ary_seg[]"); if (solidbits != NULL) { bu_bitv_free(solidbits); } if (RT_G_DEBUG&(DEBUG_ALLRAYS|DEBUG_SHOOT|DEBUG_PARTITION)) { bu_log("----------mshootray cpu=%d %d, %d lvl=%d (%s) %s ret=%d\n", ap->a_resource->re_cpu, ap->a_x, ap->a_y, ap->a_level, ap->a_purpose != (char *)0 ? ap->a_purpose : "?", status, ret); } return ret; }
/** * NOTE that the [0] element here corresponds with the caller's (1) * element. */ void BU_FORTRAN(frshot, FRSHOT)(int *nloc, /* input & output */ double *indist, /* output only */ double *outdist, int *region_ids, struct context *context, struct rt_i **rtip, /* input only */ double *pt, double *dir) { struct application ap; register struct partition *pp; int ret; register int i; RT_CHECK_RTI(*rtip); if (*nloc <= 0) { bu_log("ERROR frshot: nloc=%d\n", *nloc); *nloc = 0; return; } RT_APPLICATION_INIT(&ap); ap.a_ray.r_pt[X] = pt[0]; ap.a_ray.r_pt[Y] = pt[1]; ap.a_ray.r_pt[Z] = pt[2]; ap.a_ray.r_dir[X] = dir[0]; ap.a_ray.r_dir[Y] = dir[1]; ap.a_ray.r_dir[Z] = dir[2]; VUNITIZE(ap.a_ray.r_dir); ap.a_hit = fr_hit; ap.a_miss = fr_miss; ap.a_level = 0; ap.a_onehit = *nloc * 2; ap.a_resource = &rt_uniresource; rt_uniresource.re_magic = RESOURCE_MAGIC; ap.a_purpose = "frshot"; ap.a_rt_i = *rtip; /* * Actually fire the ray. The list of results will be linked to * fr_global_head by fr_hit(), for further use below. * * It is a bit risky to rely on the segment structures pointed to * by the partition list to still be valid, because rt_shootray * has already put them back on the free segment queue. However, * they will remain unchanged until the next call to * rt_shootray(), so copying out the data here will work fine. */ ret = rt_shootray(&ap); if (ret <= 0) { /* Signal no hits */ *nloc = 0; return; } /* Copy hit information from linked list to argument arrays */ pp = fr_global_head.pt_forw; if (pp == &fr_global_head) { *nloc = 0; return; } for (i=0; i < *nloc; i++, pp=pp->pt_forw) { register struct context *ctp; if (pp == &fr_global_head) break; indist[i] = pp->pt_inhit->hit_dist; outdist[i] = pp->pt_outhit->hit_dist; /* This might instead be reg_regionid ?? */ region_ids[i] = pp->pt_regionp->reg_bit+1; ctp = &context[i]; ctp->co_stp = pp->pt_inseg->seg_stp; VMOVE(ctp->co_vpriv, pp->pt_inhit->hit_vpriv); ctp->co_priv = pp->pt_inhit->hit_private; ctp->co_inflip = pp->pt_inflip; } *nloc = i; /* Will have been incremented above, if successful */ /* Free linked list storage */ for (pp = fr_global_head.pt_forw; pp != &fr_global_head;) { register struct partition *newpp; newpp = pp; pp = pp->pt_forw; FREE_PT(newpp, (&rt_uniresource)); } }
TSplit::~TSplit() { if (m_strBuf) FREE_PT(m_strBuf); if (m_Array) FREE_PT(m_Array); }