HIDDEN int wdb_do_paren(struct bu_list *hp) { struct tokens *tok; for (BU_LIST_FOR(tok, tokens, hp)) { struct tokens *prev, *next; if (tok->type != WDB_TOK_TREE) continue; prev = BU_LIST_PREV(tokens, &tok->l); next = BU_LIST_NEXT(tokens, &tok->l); if (prev->type !=WDB_TOK_LPAREN || next->type != WDB_TOK_RPAREN) continue; /* this is an eligible operand surrounded by parens */ BU_LIST_DEQUEUE(&next->l); bu_free((char *)next, "next"); BU_LIST_DEQUEUE(&prev->l); bu_free((char *)prev, "prev"); } if (hp->forw == hp->back && hp->forw != hp) return 1; /* done */ else if (BU_LIST_IS_EMPTY(hp)) return -1; /* empty tree!!!! */ else return 0; /* more to do */ }
void _ged_cvt_vlblock_to_solids(struct ged *gedp, struct bn_vlblock *vbp, const char *name, int copy) { size_t i; char shortname[32] = {0}; char namebuf[64] = {0}; bu_strlcpy(shortname, name, sizeof(shortname)); for (i = 0; i < vbp->nused; i++) { if (BU_LIST_IS_EMPTY(&(vbp->head[i]))) continue; snprintf(namebuf, 64, "%s%lx", shortname, vbp->rgb[i]); invent_solid(gedp->ged_gdp->gd_headDisplay, gedp->ged_wdbp->dbip, gedp->ged_create_vlist_solid_callback, gedp->ged_free_vlist_callback, namebuf, &vbp->head[i], vbp->rgb[i], copy, 0.0, 0, gedp->freesolid, 0); } }
void rt_plot_vlblock(FILE *fp, const struct bn_vlblock *vbp) { size_t i; BN_CK_VLBLOCK(vbp); for (i=0; i < vbp->nused; i++) { if (vbp->rgb[i] == 0) continue; if (BU_LIST_IS_EMPTY(&(vbp->head[i]))) continue; pl_color(fp, (vbp->rgb[i]>>16) & 0xFF, (vbp->rgb[i]>> 8) & 0xFF, (vbp->rgb[i]) & 0xFF); rt_vlist_to_uplot(fp, &(vbp->head[i])); } }
void rt_vlblock_free(struct bn_vlblock *vbp) { size_t i; BN_CK_VLBLOCK(vbp); for (i=0; i < vbp->nused; i++) { /* Release any remaining vlist storage */ if (vbp->rgb[i] == 0) continue; if (BU_LIST_IS_EMPTY(&(vbp->head[i]))) continue; BN_FREE_VLIST(vbp->free_vlist_hd, &(vbp->head[i])); } bu_free((char *)(vbp->head), "head[]"); bu_free((char *)(vbp->rgb), "rgb[]"); bu_free((char *)vbp, "bn_vlblock"); }
/* * Default keypoint in model space is established in "pt". Returns * GED_ERROR if unable to determine a keypoint, otherwise returns * GED_OK. */ int _ged_get_solid_keypoint(struct ged *const gedp, fastf_t *const pt, const struct rt_db_internal *const ip, const fastf_t *const mat) { point_t mpt; RT_CK_DB_INTERNAL(ip); switch (ip->idb_type) { case ID_CLINE: { struct rt_cline_internal *cli = (struct rt_cline_internal *)ip->idb_ptr; RT_CLINE_CK_MAGIC(cli); VMOVE(mpt, cli->v); break; } case ID_PARTICLE: { struct rt_part_internal *part = (struct rt_part_internal *)ip->idb_ptr; RT_PART_CK_MAGIC(part); VMOVE(mpt, part->part_V); break; } case ID_PIPE: { struct rt_pipe_internal *pipeip; struct wdb_pipept *pipe_seg; pipeip = (struct rt_pipe_internal *)ip->idb_ptr; RT_PIPE_CK_MAGIC(pipeip); pipe_seg = BU_LIST_FIRST(wdb_pipept, &pipeip->pipe_segs_head); VMOVE(mpt, pipe_seg->pp_coord); break; } case ID_METABALL: { struct rt_metaball_internal *metaball = (struct rt_metaball_internal *)ip->idb_ptr; struct wdb_metaballpt *metaballpt; RT_METABALL_CK_MAGIC(metaball); VSETALL(mpt, 0.0); metaballpt = BU_LIST_FIRST(wdb_metaballpt, &metaball->metaball_ctrl_head); VMOVE(mpt, metaballpt->coord); break; } case ID_ARBN: { struct rt_arbn_internal *arbn = (struct rt_arbn_internal *)ip->idb_ptr; size_t i, j, k; int good_vert = 0; RT_ARBN_CK_MAGIC(arbn); for (i = 0; i < arbn->neqn; i++) { for (j = i + 1; j < arbn->neqn; j++) { for (k = j + 1; k < arbn->neqn; k++) { if (!bn_mkpoint_3planes(mpt, arbn->eqn[i], arbn->eqn[j], arbn->eqn[k])) { size_t l; good_vert = 1; for (l = 0; l < arbn->neqn; l++) { if (l == i || l == j || l == k) continue; if (DIST_PT_PLANE(mpt, arbn->eqn[l]) > gedp->ged_wdbp->wdb_tol.dist) { good_vert = 0; break; } } if (good_vert) break; } } if (good_vert) break; } if (good_vert) break; } break; } case ID_EBM: { struct rt_ebm_internal *ebm = (struct rt_ebm_internal *)ip->idb_ptr; point_t pnt; RT_EBM_CK_MAGIC(ebm); VSETALL(pnt, 0.0); MAT4X3PNT(mpt, ebm->mat, pnt); break; } case ID_BOT: { struct rt_bot_internal *bot = (struct rt_bot_internal *)ip->idb_ptr; VMOVE(mpt, bot->vertices); break; } case ID_DSP: { struct rt_dsp_internal *dsp = (struct rt_dsp_internal *)ip->idb_ptr; point_t pnt; RT_DSP_CK_MAGIC(dsp); VSETALL(pnt, 0.0); MAT4X3PNT(mpt, dsp->dsp_stom, pnt); break; } case ID_HF: { struct rt_hf_internal *hf = (struct rt_hf_internal *)ip->idb_ptr; RT_HF_CK_MAGIC(hf); VMOVE(mpt, hf->v); break; } case ID_VOL: { struct rt_vol_internal *vol = (struct rt_vol_internal *)ip->idb_ptr; point_t pnt; RT_VOL_CK_MAGIC(vol); VSETALL(pnt, 0.0); MAT4X3PNT(mpt, vol->mat, pnt); break; } case ID_HALF: { struct rt_half_internal *haf = (struct rt_half_internal *)ip->idb_ptr; RT_HALF_CK_MAGIC(haf); VSCALE(mpt, haf->eqn, haf->eqn[H]); break; } case ID_ARB8: { struct rt_arb_internal *arb = (struct rt_arb_internal *)ip->idb_ptr; RT_ARB_CK_MAGIC(arb); VMOVE(mpt, arb->pt[0]); break; } case ID_ELL: case ID_SPH: { struct rt_ell_internal *ell = (struct rt_ell_internal *)ip->idb_ptr; RT_ELL_CK_MAGIC(ell); VMOVE(mpt, ell->v); break; } case ID_SUPERELL: { struct rt_superell_internal *superell = (struct rt_superell_internal *)ip->idb_ptr; RT_SUPERELL_CK_MAGIC(superell); VMOVE(mpt, superell->v); break; } case ID_TOR: { struct rt_tor_internal *tor = (struct rt_tor_internal *)ip->idb_ptr; RT_TOR_CK_MAGIC(tor); VMOVE(mpt, tor->v); break; } case ID_TGC: case ID_REC: { struct rt_tgc_internal *tgc = (struct rt_tgc_internal *)ip->idb_ptr; RT_TGC_CK_MAGIC(tgc); VMOVE(mpt, tgc->v); break; } case ID_GRIP: { struct rt_grip_internal *gip = (struct rt_grip_internal *)ip->idb_ptr; RT_GRIP_CK_MAGIC(gip); VMOVE(mpt, gip->center); break; } case ID_ARS: { struct rt_ars_internal *ars = (struct rt_ars_internal *)ip->idb_ptr; RT_ARS_CK_MAGIC(ars); VMOVE(mpt, &ars->curves[0][0]); break; } case ID_RPC: { struct rt_rpc_internal *rpc = (struct rt_rpc_internal *)ip->idb_ptr; RT_RPC_CK_MAGIC(rpc); VMOVE(mpt, rpc->rpc_V); break; } case ID_RHC: { struct rt_rhc_internal *rhc = (struct rt_rhc_internal *)ip->idb_ptr; RT_RHC_CK_MAGIC(rhc); VMOVE(mpt, rhc->rhc_V); break; } case ID_EPA: { struct rt_epa_internal *epa = (struct rt_epa_internal *)ip->idb_ptr; RT_EPA_CK_MAGIC(epa); VMOVE(mpt, epa->epa_V); break; } case ID_EHY: { struct rt_ehy_internal *ehy = (struct rt_ehy_internal *)ip->idb_ptr; RT_EHY_CK_MAGIC(ehy); VMOVE(mpt, ehy->ehy_V); break; } case ID_HYP: { struct rt_hyp_internal *hyp = (struct rt_hyp_internal *)ip->idb_ptr; RT_HYP_CK_MAGIC(hyp); VMOVE(mpt, hyp->hyp_Vi); break; } case ID_ETO: { struct rt_eto_internal *eto = (struct rt_eto_internal *)ip->idb_ptr; RT_ETO_CK_MAGIC(eto); VMOVE(mpt, eto->eto_V); break; } case ID_POLY: { struct rt_pg_face_internal *_poly; struct rt_pg_internal *pg = (struct rt_pg_internal *)ip->idb_ptr; RT_PG_CK_MAGIC(pg); _poly = pg->poly; VMOVE(mpt, _poly->verts); break; } case ID_SKETCH: { struct rt_sketch_internal *skt = (struct rt_sketch_internal *)ip->idb_ptr; RT_SKETCH_CK_MAGIC(skt); VMOVE(mpt, skt->V); break; } case ID_EXTRUDE: { struct rt_extrude_internal *extr = (struct rt_extrude_internal *)ip->idb_ptr; RT_EXTRUDE_CK_MAGIC(extr); if (extr->skt && extr->skt->verts) { VJOIN2(mpt, extr->V, extr->skt->verts[0][0], extr->u_vec, extr->skt->verts[0][1], extr->v_vec); } else { VMOVE(mpt, extr->V); } break; } case ID_NMG: { struct vertex *v; struct vertexuse *vu; struct edgeuse *eu; struct loopuse *lu; struct faceuse *fu; struct shell *s; struct nmgregion *r; struct model *m = (struct model *) ip->idb_ptr; NMG_CK_MODEL(m); /* set default first */ VSETALL(mpt, 0.0); if (BU_LIST_IS_EMPTY(&m->r_hd)) break; r = BU_LIST_FIRST(nmgregion, &m->r_hd); if (!r) break; NMG_CK_REGION(r); if (BU_LIST_IS_EMPTY(&r->s_hd)) break; s = BU_LIST_FIRST(shell, &r->s_hd); if (!s) break; NMG_CK_SHELL(s); if (BU_LIST_IS_EMPTY(&s->fu_hd)) fu = (struct faceuse *)NULL; else fu = BU_LIST_FIRST(faceuse, &s->fu_hd); if (fu) { NMG_CK_FACEUSE(fu); lu = BU_LIST_FIRST(loopuse, &fu->lu_hd); NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) { eu = BU_LIST_FIRST(edgeuse, &lu->down_hd); NMG_CK_EDGEUSE(eu); NMG_CK_VERTEXUSE(eu->vu_p); v = eu->vu_p->v_p; } else { vu = BU_LIST_FIRST(vertexuse, &lu->down_hd); NMG_CK_VERTEXUSE(vu); v = vu->v_p; } NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } if (BU_LIST_IS_EMPTY(&s->lu_hd)) lu = (struct loopuse *)NULL; else lu = BU_LIST_FIRST(loopuse, &s->lu_hd); if (lu) { NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) { eu = BU_LIST_FIRST(edgeuse, &lu->down_hd); NMG_CK_EDGEUSE(eu); NMG_CK_VERTEXUSE(eu->vu_p); v = eu->vu_p->v_p; } else { vu = BU_LIST_FIRST(vertexuse, &lu->down_hd); NMG_CK_VERTEXUSE(vu); v = vu->v_p; } NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } if (BU_LIST_IS_EMPTY(&s->eu_hd)) eu = (struct edgeuse *)NULL; else eu = BU_LIST_FIRST(edgeuse, &s->eu_hd); if (eu) { NMG_CK_EDGEUSE(eu); NMG_CK_VERTEXUSE(eu->vu_p); v = eu->vu_p->v_p; NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } vu = s->vu_p; if (vu) { NMG_CK_VERTEXUSE(vu); v = vu->v_p; NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } } default: VSETALL(mpt, 0.0); bu_vls_printf(gedp->ged_result_str, "get_solid_keypoint: unrecognized solid type"); return GED_ERROR; } MAT4X3PNT(pt, mat, mpt); return GED_OK; }
/** * 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; }
/** * Read a polygon file and convert it to an NMG shell * * A polygon file consists of the following: * * The first line consists of two integer numbers: the number of * points (vertices) in the file, followed by the number of polygons * in the file. This line is followed by lines for each of the * vertices. Each vertex is listed on its own line, as the 3tuple "X * Y Z". After the list of vertices comes the list of polygons. * each polygon is represented by a line containing 1) the number of * vertices in the polygon, followed by 2) the indices of the * vertices that make up the polygon. * * Implicitly returns r->s_p which is a new shell containing all the * faces from the polygon file. * * XXX This is a horrible way to do this. Lee violates his own rules * about not creating fundamental structures on his own... :-) * Retired in favor of more modern tessellation strategies. */ struct shell * nmg_polytonmg(FILE *fp, struct nmgregion *r, const struct bn_tol *tol) { int i, j, num_pts, num_facets, pts_this_face, facet; int vl_len; struct vertex **v; /* list of all vertices */ struct vertex **vl; /* list of vertices for this polygon*/ point_t p; struct shell *s; struct faceuse *fu; struct loopuse *lu; struct edgeuse *eu; plane_t plane; struct model *m; s = nmg_msv(r); m = s->r_p->m_p; nmg_kvu(s->vu_p); /* get number of points & number of facets in file */ if (fscanf(fp, "%d %d", &num_pts, &num_facets) != 2) bu_bomb("polytonmg() Error in first line of poly file\n"); else if (RTG.NMG_debug & DEBUG_POLYTO) bu_log("points: %d facets: %d\n", num_pts, num_facets); v = (struct vertex **) bu_calloc(num_pts, sizeof (struct vertex *), "vertices"); /* build the vertices */ for (i = 0; i < num_pts; ++i) { GET_VERTEX(v[i], m); v[i]->magic = NMG_VERTEX_MAGIC; } /* read in the coordinates of the vertices */ for (i=0; i < num_pts; ++i) { if (fscanf(fp, "%lg %lg %lg", &p[0], &p[1], &p[2]) != 3) bu_bomb("polytonmg() Error reading point"); else if (RTG.NMG_debug & DEBUG_POLYTO) bu_log("read vertex #%d (%g %g %g)\n", i, p[0], p[1], p[2]); nmg_vertex_gv(v[i], p); } vl = (struct vertex **)bu_calloc(vl_len=8, sizeof (struct vertex *), "vertex parameter list"); for (facet = 0; facet < num_facets; ++facet) { if (fscanf(fp, "%d", &pts_this_face) != 1) bu_bomb("polytonmg() error getting pt count for this face"); if (RTG.NMG_debug & DEBUG_POLYTO) bu_log("facet %d pts in face %d\n", facet, pts_this_face); if (pts_this_face > vl_len) { while (vl_len < pts_this_face) vl_len *= 2; vl = (struct vertex **)bu_realloc((char *)vl, vl_len*sizeof(struct vertex *), "vertex parameter list (realloc)"); } for (i=0; i < pts_this_face; ++i) { if (fscanf(fp, "%d", &j) != 1) bu_bomb("polytonmg() error getting point index for v in f"); vl[i] = v[j-1]; } fu = nmg_cface(s, vl, pts_this_face); lu = BU_LIST_FIRST(loopuse, &fu->lu_hd); /* XXX should check for vertex-loop */ eu = BU_LIST_FIRST(edgeuse, &lu->down_hd); NMG_CK_EDGEUSE(eu); if (bn_mk_plane_3pts(plane, eu->vu_p->v_p->vg_p->coord, BU_LIST_PNEXT(edgeuse, eu)->vu_p->v_p->vg_p->coord, BU_LIST_PLAST(edgeuse, eu)->vu_p->v_p->vg_p->coord, tol)) { bu_log("At %d in %s\n", __LINE__, __FILE__); bu_bomb("polytonmg() cannot make plane equation\n"); } else nmg_face_g(fu, plane); } for (i=0; i < num_pts; ++i) { if (BU_LIST_IS_EMPTY(&v[i]->vu_hd)) continue; FREE_VERTEX(v[i]); } bu_free((char *)v, "vertex array"); return s; }
struct bu_list * rt_vlblock_find(struct bn_vlblock *vbp, int r, int g, int b) { long newrgb; size_t n; size_t omax; /* old max */ BN_CK_VLBLOCK(vbp); newrgb = ((r&0xFF)<<16)|((g&0xFF)<<8)|(b&0xFF); for (n=0; n < vbp->nused; n++) { if (vbp->rgb[n] == newrgb) return &(vbp->head[n]); } if (vbp->nused < vbp->max) { /* Allocate empty slot */ n = vbp->nused++; vbp->rgb[n] = newrgb; return &(vbp->head[n]); } /************** enlarge the table ****************/ omax = vbp->max; vbp->max *= 2; /* Look for empty lists and mark for use below. */ for (n=0; n < omax; n++) if (BU_LIST_IS_EMPTY(&vbp->head[n])) vbp->head[n].forw = BU_LIST_NULL; vbp->head = (struct bu_list *)bu_realloc((genptr_t)vbp->head, vbp->max * sizeof(struct bu_list), "head[]"); vbp->rgb = (long *)bu_realloc((genptr_t)vbp->rgb, vbp->max * sizeof(long), "rgb[]"); /* re-initialize pointers in lower half */ for (n=0; n < omax; n++) { /* * Check to see if list is empty * (i.e. yellow and/or white are not used). * Note - we can't use BU_LIST_IS_EMPTY here because * the addresses of the list heads have possibly changed. */ if (vbp->head[n].forw == BU_LIST_NULL) { vbp->head[n].forw = &vbp->head[n]; vbp->head[n].back = &vbp->head[n]; } else { vbp->head[n].forw->back = &vbp->head[n]; vbp->head[n].back->forw = &vbp->head[n]; } } /* initialize upper half of memory */ for (n=omax; n < vbp->max; n++) { vbp->rgb[n] = 0; BU_LIST_INIT(&vbp->head[n]); } /* here we go again */ return rt_vlblock_find(vbp, r, g, b); }
int main (int argc, char **argv) { char *inf_name; int ch; int i; int nm_sites; int normalize = 0; /* Make all weights sum to one? */ fastf_t *coeff; fastf_t x, y, z; FILE *infp; struct bu_list site_list; struct bu_vls *tail_buf = 0; struct site *sp; BU_LIST_INIT(&site_list); while ((ch = bu_getopt(argc, argv, OPT_STRING)) != EOF) switch (ch) { case 'n': normalize = 1; break; case 's': if (sscanf(bu_optarg, "%lf %lf %lf", &x, &y, &z) != 3) { bu_log("Illegal site: '%s'\n", bu_optarg); print_usage(); } enqueue_site(&site_list, x, y, z); break; case 't': if (tail_buf == 0) /* Only initialize it once */ tail_buf = bu_vls_vlsinit(); break; case '?': default: print_usage(); } switch (argc - bu_optind) { case 0: inf_name = "stdin"; infp = stdin; break; case 1: inf_name = argv[bu_optind++]; if ((infp = fopen(inf_name, "r")) == NULL) bu_exit (1, "Cannot open file '%s'\n", inf_name); break; default: print_usage(); } if (BU_LIST_IS_EMPTY(&site_list)) { enqueue_site(&site_list, (fastf_t) 1.0, (fastf_t) 0.0, (fastf_t) 0.0); enqueue_site(&site_list, (fastf_t) 0.0, (fastf_t) 1.0, (fastf_t) 0.0); enqueue_site(&site_list, (fastf_t) 0.0, (fastf_t) 0.0, (fastf_t) 1.0); } nm_sites = 0; for (BU_LIST_FOR(sp, site, &site_list)) ++nm_sites; coeff = (fastf_t *) bu_malloc(nm_sites * sizeof(fastf_t), "coefficient array"); while (read_point(infp, coeff, nm_sites, normalize, tail_buf) != EOF) { x = y = z = 0.0; i = 0; for (BU_LIST_FOR(sp, site, &site_list)) { x += sp -> s_x * coeff[i]; y += sp -> s_y * coeff[i]; z += sp -> s_z * coeff[i]; ++i; } bu_flog(stdout, "%g %g %g", x, y, z); if (tail_buf) bu_flog(stdout, "%s", bu_vls_addr(tail_buf)); bu_flog(stdout, "\n"); } return 0; }
/** * Make a life-and-death decision on every element of a shell. * Descend the "great chain of being" from the face to loop to edge to * vertex, saving or demoting along the way. * * Note that there is no moving of items from one shell to another. */ HIDDEN void nmg_eval_shell(register struct shell *s, struct nmg_bool_state *bs) { struct faceuse *fu; struct faceuse *nextfu; struct loopuse *lu; struct loopuse *nextlu; struct edgeuse *eu; struct edgeuse *nexteu; struct vertexuse *vu; int loops_retained; NMG_CK_SHELL(s); BN_CK_TOL(bs->bs_tol); if (RTG.NMG_debug & DEBUG_VERIFY) nmg_vshell(&s->r_p->s_hd, s->r_p); /* * For each face in the shell, process all the loops in the face, * and then handle the face and all loops as a unit. */ nmg_eval_plot(bs, nmg_eval_count++); /* debug */ fu = BU_LIST_FIRST(faceuse, &s->fu_hd); while (BU_LIST_NOT_HEAD(fu, &s->fu_hd)) { NMG_CK_FACEUSE(fu); nextfu = BU_LIST_PNEXT(faceuse, fu); /* Faceuse mates will be handled at same time as OT_SAME fu */ if (fu->orientation != OT_SAME) { fu = nextfu; continue; } if (fu->fumate_p == nextfu) nextfu = BU_LIST_PNEXT(faceuse, nextfu); /* Consider this face */ NMG_CK_FACE(fu->f_p); loops_retained = 0; lu = BU_LIST_FIRST(loopuse, &fu->lu_hd); while (BU_LIST_NOT_HEAD(lu, &fu->lu_hd)) { NMG_CK_LOOPUSE(lu); nextlu = BU_LIST_PNEXT(loopuse, lu); if (lu->lumate_p == nextlu) nextlu = BU_LIST_PNEXT(loopuse, nextlu); NMG_CK_LOOP(lu->l_p); nmg_ck_lu_orientation(lu, bs->bs_tol); switch (nmg_eval_action(&lu->l_p->magic, bs)) { case BACTION_KILL: /* Kill by demoting loop to edges */ if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC) { /* loop of single vertex */ (void)nmg_klu(lu); } else if (nmg_demote_lu(lu) == 0) { nmg_eval_plot(bs, nmg_eval_count++); /* debug */ } lu = nextlu; continue; case BACTION_RETAIN: loops_retained++; break; default: bu_bomb("nmg_eval_shell() bad BACTION\n"); } lu = nextlu; } if (RTG.NMG_debug & DEBUG_BOOLEVAL) bu_log("faceuse %p loops retained=%d\n", (void *)fu, loops_retained); if (RTG.NMG_debug & DEBUG_VERIFY) nmg_vshell(&s->r_p->s_hd, s->r_p); /* * Here, faceuse will have 0 or more loopuses still in it. * Decide the fate of the face; if the face dies, * then any remaining loops, edges, etc., will die too. */ if (BU_LIST_IS_EMPTY(&fu->lu_hd)) { if (loops_retained) bu_bomb("nmg_eval_shell() empty faceuse with retained loops?\n"); /* faceuse is empty, face & mate die */ if (RTG.NMG_debug & DEBUG_BOOLEVAL) bu_log("faceuse %p empty, kill\n", (void *)fu); nmg_kfu(fu); /* kill face & mate, dequeue from shell */ if (RTG.NMG_debug & DEBUG_VERIFY) nmg_vshell(&s->r_p->s_hd, s->r_p); nmg_eval_plot(bs, nmg_eval_count++); /* debug */ fu = nextfu; continue; } if (loops_retained <= 0) { nmg_pr_fu(fu, (char *)NULL); bu_bomb("nmg_eval_shell() non-empty faceuse, no loops retained?\n"); } fu = nextfu; } if (RTG.NMG_debug & DEBUG_VERIFY) nmg_vshell(&s->r_p->s_hd, s->r_p); /* * For each loop in the shell, process. * Each loop is either a wire-loop, or a vertex-with-self-loop. * Only consider wire loops here. */ nmg_eval_plot(bs, nmg_eval_count++); /* debug */ lu = BU_LIST_FIRST(loopuse, &s->lu_hd); while (BU_LIST_NOT_HEAD(lu, &s->lu_hd)) { NMG_CK_LOOPUSE(lu); nextlu = BU_LIST_PNEXT(loopuse, lu); if (lu->lumate_p == nextlu) nextlu = BU_LIST_PNEXT(loopuse, nextlu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC) { /* ignore vertex-with-self-loop */ lu = nextlu; continue; } NMG_CK_LOOP(lu->l_p); switch (nmg_eval_action(&lu->l_p->magic, bs)) { case BACTION_KILL: /* Demote the loopuse into wire edges */ /* kill loop & mate */ if (nmg_demote_lu(lu) == 0) nmg_eval_plot(bs, nmg_eval_count++); /* debug */ lu = nextlu; continue; case BACTION_RETAIN: break; default: bu_bomb("nmg_eval_shell() bad BACTION\n"); } lu = nextlu; } if (RTG.NMG_debug & DEBUG_VERIFY) nmg_vshell(&s->r_p->s_hd, s->r_p); /* * For each wire-edge in the shell, ... */ nmg_eval_plot(bs, nmg_eval_count++); /* debug */ eu = BU_LIST_FIRST(edgeuse, &s->eu_hd); while (BU_LIST_NOT_HEAD(eu, &s->eu_hd)) { NMG_CK_EDGEUSE(eu); nexteu = BU_LIST_PNEXT(edgeuse, eu); /* may be head */ if (eu->eumate_p == nexteu) nexteu = BU_LIST_PNEXT(edgeuse, nexteu); /* Consider this edge */ NMG_CK_EDGE(eu->e_p); switch (nmg_eval_action(&eu->e_p->magic, bs)) { case BACTION_KILL: /* Demote the edegeuse (and mate) into vertices */ if (nmg_demote_eu(eu) == 0) nmg_eval_plot(bs, nmg_eval_count++); /* debug */ eu = nexteu; continue; case BACTION_RETAIN: break; default: bu_bomb("nmg_eval_shell() bad BACTION\n"); } eu = nexteu; } /* * For each lone vertex-with-self-loop, process. * Note that these are intermixed in the loop list. * Each loop is either a wire-loop, or a vertex-with-self-loop. * Only consider cases of vertex-with-self-loop here. * * This case has to be handled separately, because a wire-loop * may be demoted to a set of wire-edges above, some of which * may be retained. The non-retained wire-edges may in turn * be demoted into vertex-with-self-loop objects above, * which will be processed here. */ nmg_eval_plot(bs, nmg_eval_count++); /* debug */ lu = BU_LIST_FIRST(loopuse, &s->lu_hd); while (BU_LIST_NOT_HEAD(lu, &s->lu_hd)) { NMG_CK_LOOPUSE(lu); nextlu = BU_LIST_PNEXT(loopuse, lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_VERTEXUSE_MAGIC) { /* ignore any remaining wire-loops */ lu = nextlu; continue; } if (nextlu == lu->lumate_p) nextlu = BU_LIST_PNEXT(loopuse, nextlu); vu = BU_LIST_PNEXT(vertexuse, &lu->down_hd); NMG_CK_VERTEXUSE(vu); NMG_CK_VERTEX(vu->v_p); switch (nmg_eval_action(&vu->v_p->magic, bs)) { case BACTION_KILL: /* Eliminate the loopuse, and mate */ nmg_klu(lu); lu = nextlu; continue; case BACTION_RETAIN: break; default: bu_bomb("nmg_eval_shell() bad BACTION\n"); } lu = nextlu; } if (RTG.NMG_debug & DEBUG_VERIFY) nmg_vshell(&s->r_p->s_hd, s->r_p); /* * Final case: shell of a single vertexuse */ vu = s->vu_p; if (vu) { NMG_CK_VERTEXUSE(vu); NMG_CK_VERTEX(vu->v_p); switch (nmg_eval_action(&vu->v_p->magic, bs)) { case BACTION_KILL: nmg_kvu(vu); nmg_eval_plot(bs, nmg_eval_count++); /* debug */ s->vu_p = (struct vertexuse *)0; /* sanity */ break; case BACTION_RETAIN: break; default: bu_bomb("nmg_eval_shell() bad BACTION\n"); } } if (RTG.NMG_debug & DEBUG_VERIFY) nmg_vshell(&s->r_p->s_hd, s->r_p); nmg_eval_plot(bs, nmg_eval_count++); /* debug */ }
int main(int argc, char **argv) { int c; int i; struct pshell *psh; struct pbar *pbp; struct wmember head; struct wmember all_head; char *nastran_file = "Converted from NASTRAN file (stdin)"; bu_setprogname(argv[0]); fpin = stdin; units = INCHES; /* FIXME: These need to be improved */ tol.magic = BN_TOL_MAGIC; tol.dist = 0.0005; tol.dist_sq = tol.dist * tol.dist; tol.perp = 1e-6; tol.para = 1 - tol.perp; while ((c=bu_getopt(argc, argv, "x:X:t:ni:o:mh?")) != -1) { switch (c) { case 'x': sscanf(bu_optarg, "%x", (unsigned int *)&RTG.debug); bu_printb("librt RT_G_DEBUG", RT_G_DEBUG, DEBUG_FORMAT); bu_log("\n"); break; case 'X': sscanf(bu_optarg, "%x", (unsigned int *)&RTG.NMG_debug); bu_printb("librt RTG.NMG_debug", RTG.NMG_debug, NMG_DEBUG_FORMAT); bu_log("\n"); break; case 't': /* calculational tolerance */ tol.dist = atof(bu_optarg); tol.dist_sq = tol.dist * tol.dist; break; case 'n': polysolids = 0; break; case 'm': units = MM; break; case 'i': fpin = fopen(bu_optarg, "rb"); if (fpin == (FILE *)NULL) { bu_log("Cannot open NASTRAN file (%s) for reading!\n", bu_optarg); bu_exit(1, Usage, argv[0]); } nastran_file = bu_optarg; break; case 'o': output_file = bu_optarg; break; default: bu_exit(1, Usage, argv[0]); } } fpout = wdb_fopen(output_file); if (fpout == NULL) { bu_log("Cannot open BRL-CAD file (%s) for writing!\n", output_file); bu_exit(1, Usage, argv[0]); } if (!fpin || !fpout) { bu_exit(1, Usage, argv[0]); } line = (char *)bu_malloc(MAX_LINE_SIZE, "line"); next_line = (char *)bu_malloc(MAX_LINE_SIZE, "next_line"); prev_line = (char *)bu_malloc(MAX_LINE_SIZE, "prev_line"); curr_rec = (char **)bu_calloc(NO_OF_FIELDS, sizeof(char *), "curr_rec"); for (i=0; i<NO_OF_FIELDS; i++) curr_rec[i] = (char *)bu_malloc(sizeof(char)*FIELD_LENGTH, "curr_rec[i]"); prev_rec = (char **)bu_calloc(NO_OF_FIELDS, sizeof(char *), "prev_rec"); for (i=0; i<NO_OF_FIELDS; i++) prev_rec[i] = (char *)bu_malloc(sizeof(char)*FIELD_LENGTH, "prev_rec[i]"); /* first pass, find start of NASTRAN "bulk data" */ start_off = (-1); bulk_data_start_line = 0; while (bu_fgets(line, MAX_LINE_SIZE, fpin)) { bulk_data_start_line++; if (bu_strncmp(line, "BEGIN BULK", 10)) continue; start_off = bu_ftell(fpin); break; } if (start_off < 0) { bu_log("Cannot find start of bulk data in NASTRAN file!\n"); bu_exit(1, Usage, argv[0]); } /* convert BULK data deck into something reasonable */ fptmp = bu_temp_file(NULL, 0); if (fptmp == NULL) { perror(argv[0]); bu_exit(1, "Cannot open temporary file\n"); } convert_input(); /* initialize some lists */ BU_LIST_INIT(&coord_head.l); BU_LIST_INIT(&pbar_head.l); BU_LIST_INIT(&pshell_head.l); BU_LIST_INIT(&all_head.l); nmg_model = (struct model *)NULL; /* count grid points */ bu_fseek(fptmp, 0, SEEK_SET); while (bu_fgets(line, MAX_LINE_SIZE, fptmp)) { if (!bu_strncmp(line, "GRID", 4)) grid_count++; } if (!grid_count) { bu_exit(1, "No geometry in this NASTRAN file!\n"); } /* get default values and properties */ bu_fseek(fptmp, 0, SEEK_SET); while (get_next_record(fptmp, 1, 0)) { if (!bu_strncmp(curr_rec[0], "BAROR", 5)) { /* get BAR defaults */ bar_def_pid = atoi(curr_rec[2]); } else if (!bu_strncmp(curr_rec[0], "PBAR", 4)) { struct pbar *pb; BU_ALLOC(pb, struct pbar); pb->pid = atoi(curr_rec[1]); pb->mid = atoi(curr_rec[2]); pb->area = atof(curr_rec[3]); BU_LIST_INIT(&pb->head.l); BU_LIST_INSERT(&pbar_head.l, &pb->l); } else if (!bu_strncmp(curr_rec[0], "PSHELL", 6)) { BU_ALLOC(psh, struct pshell); psh->s = (struct shell *)NULL; psh->pid = atoi(curr_rec[1]); psh->mid = atoi(curr_rec[2]); psh->thick = atof(curr_rec[3]); BU_LIST_INSERT(&pshell_head.l, &psh->l); pshell_count++; } } /* allocate storage for grid points */ g_pts = (struct grid_point *)bu_calloc(grid_count, sizeof(struct grid_point), "grid points"); /* get all grid points */ bu_fseek(fptmp, 0, SEEK_SET); while (get_next_record(fptmp, 1, 0)) { int gid; int cid; double tmp[3]; if (bu_strncmp(curr_rec[0], "GRID", 4)) continue; gid = atoi(curr_rec[1]); cid = atoi(curr_rec[2]); for (i=0; i<3; i++) { tmp[i] = atof(curr_rec[i+3]); } g_pts[grid_used].gid = gid; g_pts[grid_used].cid = cid; g_pts[grid_used].v = (struct vertex **)bu_calloc(pshell_count + 1, sizeof(struct vertex *), "g_pts vertex array"); VMOVE(g_pts[grid_used].pt, tmp); grid_used++; } /* find coordinate systems */ bu_fseek(fptmp, 0, SEEK_SET); while (get_next_record(fptmp, 1, 0)) { if (bu_strncmp(curr_rec[0], "CORD", 4)) continue; get_coord_sys(); } /* convert everything to BRL-CAD coordinate system */ i = 0; while (convert_all_cs() || convert_all_pts()) { i++; if (i > 10) { bu_exit(1, "Cannot convert to default coordinate system, check for circular definition\n"); } } mk_id(fpout, nastran_file); /* get elements */ bu_fseek(fptmp, 0, SEEK_SET); while (get_next_record(fptmp, 1, 0)) { if (!bu_strncmp(curr_rec[0], "CBAR", 4)) get_cbar(); else if (!bu_strncmp(curr_rec[0], "CROD", 4)) get_cbar(); else if (!bu_strncmp(curr_rec[0], "CTRIA3", 6)) get_ctria3(); else if (!bu_strncmp(curr_rec[0], "CQUAD4", 6)) get_cquad4(); } if (nmg_model) { nmg_rebound(nmg_model, &tol); if (polysolids) mk_bot_from_nmg(fpout, "pshell.0", nmg_shell); else mk_nmg(fpout, "pshell.0", nmg_model); } BU_LIST_INIT(&head.l); for (BU_LIST_FOR(psh, pshell, &pshell_head.l)) { struct model *m; char name[NAMESIZE+1]; if (!psh->s) continue; m = nmg_find_model(&psh->s->l.magic); nmg_rebound(m, &tol); nmg_fix_normals(psh->s, &tol); if (psh->thick > tol.dist) { nmg_model_face_fuse(m, &tol); nmg_hollow_shell(psh->s, psh->thick*conv[units], 1, &tol); } sprintf(name, "pshell.%d", psh->pid); if (polysolids) mk_bot_from_nmg(fpout, name, psh->s); else mk_nmg(fpout, name, m); mk_addmember(name, &head.l, NULL, WMOP_UNION); } if (BU_LIST_NON_EMPTY(&head.l)) { mk_lfcomb(fpout, "shells", &head, 0); mk_addmember("shells", &all_head.l, NULL, WMOP_UNION); } BU_LIST_INIT(&head.l); for (BU_LIST_FOR(pbp, pbar, &pbar_head.l)) { char name[NAMESIZE+1]; if (BU_LIST_IS_EMPTY(&pbp->head.l)) continue; sprintf(name, "pbar_group.%d", pbp->pid); mk_lfcomb(fpout, name, &pbp->head, 0); mk_addmember(name, &head.l, NULL, WMOP_UNION); } if (BU_LIST_NON_EMPTY(&head.l)) { mk_lfcomb(fpout, "pbars", &head, 0); mk_addmember("pbars", &all_head.l, NULL, WMOP_UNION); } if (BU_LIST_NON_EMPTY(&all_head.l)) { mk_lfcomb(fpout, "all", &all_head, 0); } wdb_close(fpout); return 0; }
/** * Make a list of all edgeuses which are at the same distance as the * first element on the list. Toss out opposing pairs of edgeuses of the * same edge. * */ HIDDEN void make_near_list(struct edge_info *edge_list, struct bu_list *near1, const struct bn_tol *tol) { struct edge_info *ei; struct edge_info *ei_p; struct edge_info *tmp; fastf_t dist; BU_CK_LIST_HEAD(&edge_list->l); BU_CK_LIST_HEAD(near1); /* toss opposing pairs of uses of the same edge from the list */ ei = BU_LIST_FIRST(edge_info, &edge_list->l); while (BU_LIST_NOT_HEAD(&ei->l, &edge_list->l)) { NMG_CK_EI(ei); ei_p = BU_LIST_FIRST(edge_info, &edge_list->l); while (BU_LIST_NOT_HEAD(&ei_p->l, &edge_list->l)) { NMG_CK_EI(ei_p); NMG_CK_VED(ei_p->ved_p); /* if we've found an opposing use of the same * edge toss the pair of them */ if (ei_p->ved_p->magic_p == ei->ved_p->magic_p && ei_p->eu_p->eumate_p->vu_p->v_p == ei->eu_p->vu_p->v_p && ei_p->eu_p->vu_p->v_p == ei->eu_p->eumate_p->vu_p->v_p) { if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU)) { bu_log("tossing edgeuse pair:\n"); bu_log("(%g %g %g) -> (%g %g %g)\n", V3ARGS(ei->eu_p->vu_p->v_p->vg_p->coord), V3ARGS(ei->eu_p->eumate_p->vu_p->v_p->vg_p->coord)); bu_log("(%g %g %g) -> (%g %g %g)\n", V3ARGS(ei_p->eu_p->vu_p->v_p->vg_p->coord), V3ARGS(ei_p->eu_p->eumate_p->vu_p->v_p->vg_p->coord)); } tmp = ei_p; ei_p = BU_LIST_PLAST(edge_info, &ei_p->l); BU_LIST_DEQUEUE(&tmp->l); bu_free((char *)tmp, "edge info struct"); tmp = ei; ei = BU_LIST_PLAST(edge_info, &ei->l); BU_LIST_DEQUEUE(&tmp->l); bu_free((char *)tmp, "edge info struct"); break; } ei_p = BU_LIST_PNEXT(edge_info, &ei_p->l); } ei = BU_LIST_PNEXT(edge_info, &ei->l); } if (BU_LIST_IS_EMPTY(&edge_list->l)) return; ei = BU_LIST_FIRST(edge_info, &edge_list->l); NMG_CK_EI(ei); NMG_CK_VED(ei->ved_p); dist = ei->ved_p->dist; /* create "near" list with all ei's at this dist */ for (BU_LIST_FOR(ei, edge_info, &edge_list->l)) { NMG_CK_EI(ei); NMG_CK_VED(ei->ved_p); if (NEAR_EQUAL(ei->ved_p->dist, dist, tol->dist_sq)) { ei_p = BU_LIST_PLAST(edge_info, &ei->l); BU_LIST_DEQUEUE(&ei->l); BU_LIST_APPEND(near1, &ei->l); ei = ei_p; } } if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU)) { bu_log("dist %g near list\n", dist); for (BU_LIST_FOR(ei, edge_info, near1)) { bu_log("\t(%g %g %g) -> (%g %g %g)\n", V3ARGS(ei->eu_p->vu_p->v_p->vg_p->coord), V3ARGS(ei->eu_p->eumate_p->vu_p->v_p->vg_p->coord)); bu_log("\tdist:%g class:%s status:%d\n\t\tv1(%g %g %g) v2(%g %g %g)\n", ei->ved_p->dist, nmg_class_name(ei->nmg_class), ei->ved_p->status, V3ARGS(ei->ved_p->v1->vg_p->coord), V3ARGS(ei->ved_p->v2->vg_p->coord)); bu_log("\tei->ved_p->magic_p=%p, ei->eu_p->vu_p=%p, ei->eu_p->eumate_p->vu_p=%p\n", (void *)ei->ved_p->magic_p, (void *)ei->eu_p->vu_p, (void *)ei->eu_p->eumate_p->vu_p); } }