/** * Creates one metaball object that includes all points from an * existing list (in 'av') of named metaballs. This routine creates * an rt_metaball_internal object directly via LIBRT given it requires * reading existing metaballs from the database. */ static void mix_balls(struct db_i *dbip, const char *name, int ac, const char *av[]) { int i; struct directory *dp; struct rt_metaball_internal *newmp; RT_CK_DBI(dbip); /* allocate a struct rt_metaball_internal object that we'll * manually fill in with points from the other metaballs being * joined together. */ BU_ALLOC(newmp, struct rt_metaball_internal); newmp->magic = RT_METABALL_INTERNAL_MAGIC; newmp->threshold = 1.0; newmp->method = 1; BU_LIST_INIT(&newmp->metaball_ctrl_head); bu_log("Combining together the following metaballs:\n"); for (i = 0; i < ac; i++) { struct rt_db_internal dir; struct rt_metaball_internal *mp; struct wdb_metaballpt *mpt; /* get a handle on the existing database object */ bu_log("\t%s\n", av[i]); dp = db_lookup(dbip, av[i], 1); if (!dp) { bu_log("Unable to find %s\n", av[i]); continue; } /* load the existing database object */ if (rt_db_get_internal(&dir, dp, dbip, NULL, &rt_uniresource) < 0) { bu_log("Unable to load %s\n", av[i]); continue; } /* access the metaball-specific internal structure */ mp = (struct rt_metaball_internal *)dir.idb_ptr; RT_METABALL_CK_MAGIC(mp); /* iterate over each point in that database object and add it * to our new metaball. */ for (BU_LIST_FOR(mpt, wdb_metaballpt, &mp->metaball_ctrl_head)) { bu_log("Adding point (%lf %lf %lf)\n", V3ARGS(mpt->coord)); rt_metaball_add_point(newmp, (const point_t *)&mpt->coord, mpt->fldstr, mpt->sweat); } } bu_log("Joining balls together and creating [%s] object\n", name); /* write out new "mega metaball" out to disk */ dbip->dbi_wdbp = wdb_dbopen(dbip, RT_WDB_TYPE_DB_DISK); wdb_export(dbip->dbi_wdbp, name, newmp, ID_METABALL, 1.0); }
/** * used for db put/asc2g */ int rt_metaball_adjust(struct bu_vls *logstr, struct rt_db_internal *intern, int argc, const char **argv) { struct rt_metaball_internal *mb; const char *pts; const char *pend; double thresh; if (argc != 3) { bu_vls_printf(logstr, "Invalid number of arguments: %d\n", argc); return BRLCAD_ERROR; } RT_CK_DB_INTERNAL(intern); mb = (struct rt_metaball_internal *)intern->idb_ptr; RT_METABALL_CK_MAGIC(mb); if ( strlen(*argv) != 1 || (**argv < '0' || **argv > '2') ) { bu_vls_printf(logstr, "Invalid method type, must be one of 0, 1, or 2."); return BRLCAD_ERROR; } mb->method = *argv[0] - '0'; sscanf(argv[1], "%lG", &thresh); mb->threshold = thresh; BU_LIST_INIT(&mb->metaball_ctrl_head); pts = argv[2]; pend = pts + strlen(pts); while (1) { int len; double xyz[3]; double fldstr, goo; point_t loc; const point_t *locp = (const point_t *)&loc; while ( pts < pend && *pts != '{' ) ++pts; if (pts >= pend) break; len = sscanf(pts, "{%lG %lG %lG %lG %lG}", &xyz[0], &xyz[1], &xyz[2], &fldstr, &goo); VMOVE(loc, xyz); if (len == EOF) break; if (len != 5) { bu_vls_printf(logstr, "Failed to parse point information: \"%s\"", pts); return BRLCAD_ERROR; } pts++; if (rt_metaball_add_point (mb, locp, fldstr, goo)) { bu_vls_printf(logstr, "Failure adding point: {%f %f %f %f %f}", V3ARGS(loc), fldstr, goo); return BRLCAD_ERROR; } } return BRLCAD_OK; }
/** * prep and build bounding volumes... unfortunately, generating the * bounding sphere is too 'loose' (I think) and O(n^2). */ int rt_metaball_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip) { struct rt_metaball_internal *mb, *nmb; struct wdb_metaballpt *mbpt, *nmbpt; fastf_t minfstr = +INFINITY; if (rtip) RT_CK_RTI(rtip); mb = (struct rt_metaball_internal *)ip->idb_ptr; RT_METABALL_CK_MAGIC(mb); /* generate a copy of the metaball */ BU_ALLOC(nmb, struct rt_metaball_internal); nmb->magic = RT_METABALL_INTERNAL_MAGIC; BU_LIST_INIT(&nmb->metaball_ctrl_head); nmb->threshold = mb->threshold; nmb->method = mb->method; /* and copy the list of control points */ for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head)) { BU_ALLOC(nmbpt, struct wdb_metaballpt); nmbpt->fldstr = mbpt->fldstr; if (mbpt->fldstr < minfstr) minfstr = mbpt->fldstr; nmbpt->sweat = mbpt->sweat; VMOVE(nmbpt->coord, mbpt->coord); BU_LIST_INSERT(&nmb->metaball_ctrl_head, &nmbpt->l); } /* find the bounding sphere */ stp->st_aradius = rt_metaball_get_bounding_sphere(&stp->st_center, mb->threshold, mb); stp->st_bradius = stp->st_aradius * 1.01; /* XXX magic numbers, increase if scalloping is observed. :(*/ nmb->initstep = minfstr / 2.0; if (nmb->initstep < (stp->st_aradius / 200.0)) nmb->initstep = (stp->st_aradius / 200.0); else if (nmb->initstep > (stp->st_aradius / 10.0)) nmb->initstep = (stp->st_aradius / 10.0); nmb->finalstep = /*stp->st_aradius * */minfstr / 1e5; /* generate a bounding box around the sphere... * XXX this can be optimized greatly to reduce the BSP presence... */ if (rt_metaball_bbox(ip, &(stp->st_min), &(stp->st_max), &rtip->rti_tol)) return 1; stp->st_specific = (void *)nmb; return 0; }
/* main point evaluation function, to be exposed to the ugly outside * world. */ fastf_t rt_metaball_point_value(const point_t *p, const struct rt_metaball_internal *mb) { RT_METABALL_CK_MAGIC(mb); switch (mb->method) { case METABALL_METABALL: return rt_metaball_point_value_metaball(p, &mb->metaball_ctrl_head); case METABALL_ISOPOTENTIAL: return rt_metaball_point_value_iso(p, &mb->metaball_ctrl_head); case METABALL_BLOB: return rt_metaball_point_value_blob(p, &mb->metaball_ctrl_head); default: break; } return 0; }
void rt_metaball_print(register const struct soltab *stp) { int metaball_count = 0; struct rt_metaball_internal *mb; struct wdb_metaballpt *mbpt; mb = (struct rt_metaball_internal *)stp->st_specific; RT_METABALL_CK_MAGIC(mb); for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head)) ++metaball_count; bu_log("Metaball with %d points and a threshold of %g (%s rendering)\n", metaball_count, mb->threshold, rt_metaball_lookup_type_name(mb->method)); metaball_count = 0; for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head)) bu_log("\t%d: %g field strength at (%g, %g, %g) and 'goo' of %g\n", ++metaball_count, mbpt->fldstr, V3ARGS(mbpt->coord), mbpt->sweat); return; }
/** * Calculate a bounding RPP around a metaball */ int rt_metaball_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *UNUSED(tol)) { struct rt_metaball_internal *mb; point_t center; fastf_t radius; mb = (struct rt_metaball_internal *)ip->idb_ptr; RT_METABALL_CK_MAGIC(mb); VSETALL(center, 0); radius = rt_metaball_get_bounding_sphere(¢er, mb->threshold, mb); VSET((*min), center[X] - radius, center[Y] - radius, center[Z] - radius); VSET((*max), center[X] + radius, center[Y] + radius, center[Z] + radius); return 0; }
/** * R T _ M E T A B A L L _ G E T * * db get/g2asc */ int rt_metaball_get(struct bu_vls *logstr, const struct rt_db_internal *intern, const char *UNUSED(attr)) { struct rt_metaball_internal *mb = (struct rt_metaball_internal *)intern->idb_ptr; struct wdb_metaballpt *mbpt = NULL; RT_METABALL_CK_MAGIC(mb); /* write crap in */ bu_vls_printf(logstr, "metaball %d %.25G {", mb->method, mb->threshold); for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head)) bu_vls_printf(logstr, "{%.25G %.25G %.25G %.25G %.25G}", V3ARGS(mbpt->coord), mbpt->fldstr, mbpt->sweat); bu_vls_printf(logstr, "}"); return 0; }
/** * Free the storage associated with the rt_db_internal version of this * solid. This only effects the in-memory copy. */ void rt_metaball_ifree(struct rt_db_internal *ip) { register struct rt_metaball_internal *metaball; register struct wdb_metaballpt *mbpt; RT_CK_DB_INTERNAL(ip); metaball = (struct rt_metaball_internal*)ip->idb_ptr; RT_METABALL_CK_MAGIC(metaball); if (metaball->metaball_ctrl_head.magic != 0) while (BU_LIST_WHILE(mbpt, wdb_metaballpt, &metaball->metaball_ctrl_head)) { BU_LIST_DEQUEUE(&(mbpt->l)); BU_PUT(mbpt, struct wdb_metaballpt); } bu_free(ip->idb_ptr, "metaball ifree"); ip->idb_ptr = ((void *)0); }
/** * storage is something like * long numpoints * long method * fastf_t threshold * fastf_t X1 (start point) * fastf_t Y1 * fastf_t Z1 * fastf_t fldstr1 * fastf_t sweat1 (end point) * fastf_t X2 (start point) * ... */ int rt_metaball_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip) { struct rt_metaball_internal *mb; struct wdb_metaballpt *mbpt; int metaball_count = 0, i = 1; /* must be double for import and export */ double *buf = NULL; if (dbip) RT_CK_DBI(dbip); RT_CK_DB_INTERNAL(ip); if (ip->idb_type != ID_METABALL) return -1; mb = (struct rt_metaball_internal *)ip->idb_ptr; RT_METABALL_CK_MAGIC(mb); if (mb->metaball_ctrl_head.magic == 0) return -1; /* Count number of points */ for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head)) metaball_count++; BU_CK_EXTERNAL(ep); ep->ext_nbytes = SIZEOF_NETWORK_DOUBLE*(1+5*metaball_count) + 2*SIZEOF_NETWORK_LONG; ep->ext_buf = (uint8_t *)bu_malloc(ep->ext_nbytes, "metaball external"); if (ep->ext_buf == NULL) bu_bomb("Failed to allocate DB space!\n"); *(uint32_t *)ep->ext_buf = htonl(metaball_count); *(uint32_t *)(ep->ext_buf + SIZEOF_NETWORK_LONG) = htonl(mb->method); /* pack the point data */ buf = (double *)bu_malloc((metaball_count*5+1)*SIZEOF_NETWORK_DOUBLE, "rt_metaball_export5: buf"); buf[0] = mb->threshold; for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head), i+=5) { VSCALE(&buf[i], mbpt->coord, local2mm); buf[i+3] = mbpt->fldstr * local2mm; buf[i+4] = mbpt->sweat; } bu_cv_htond((unsigned char *)ep->ext_buf + 2*SIZEOF_NETWORK_LONG, (unsigned char *)buf, 1 + 5 * metaball_count); bu_free(buf, "rt_metaball_export5: buf"); return 0; }
/** * Make human-readable formatted presentation of this solid. First * line describes type of solid. Additional lines are indented one * tab, and give parameter values. */ int rt_metaball_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double UNUSED(mm2local)) { int metaball_count = 0; char buf[BUFSIZ]; struct rt_metaball_internal *mb; struct wdb_metaballpt *mbpt; RT_CK_DB_INTERNAL(ip); mb = (struct rt_metaball_internal *)ip->idb_ptr; RT_METABALL_CK_MAGIC(mb); for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head)) metaball_count++; snprintf(buf, BUFSIZ, "Metaball with %d points and a threshold of %g (%s rendering)\n", metaball_count, mb->threshold, rt_metaball_lookup_type_name(mb->method)); bu_vls_strcat(str, buf); if (!verbose) return 0; metaball_count = 0; for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head)) { switch (mb->method) { case METABALL_ISOPOTENTIAL: snprintf(buf, BUFSIZ, "\t%d: %g field strength at (%g, %g, %g)\n", ++metaball_count, mbpt->fldstr, V3ARGS(mbpt->coord)); break; case METABALL_METABALL: case METABALL_BLOB: snprintf(buf, BUFSIZ, "\t%d: %g field strength at (%g, %g, %g) and blobbiness factor of %g\n", ++metaball_count, mbpt->fldstr, V3ARGS(mbpt->coord), mbpt->sweat); break; default: bu_bomb("Bad metaball method"); /* asplode */ } bu_vls_strcat(str, buf); } return 0; }
int rt_metaball_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *UNUSED(tol), const struct rt_view_info *UNUSED(info)) { struct rt_metaball_internal *mb; struct wdb_metaballpt *mbpt; point_t bsc; fastf_t rad; BU_CK_LIST_HEAD(vhead); RT_CK_DB_INTERNAL(ip); mb = (struct rt_metaball_internal *)ip->idb_ptr; RT_METABALL_CK_MAGIC(mb); rad = rt_metaball_get_bounding_sphere(&bsc, mb->threshold, mb); /* cope with the case where 0 points are defined. */ if (rad<0) return 0; #if PLOT_THE_BIG_BOUNDING_SPHERE rt_metaball_plot_sph(vhead, &bsc, rad); #endif for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head)) rt_metaball_plot_sph(vhead, &mbpt->coord, mbpt->fldstr / mb->threshold); return 0; }
/* * 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; }
/** * R T _ M E T A B A L L _ T E S S * * Tessellate a metaball. */ int rt_metaball_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol) { struct rt_metaball_internal *mb; fastf_t mtol, radius; point_t center, min, max; fastf_t i, j, k, finalstep = +INFINITY; struct bu_vls times = BU_VLS_INIT_ZERO; struct wdb_metaballpt *mbpt; struct shell *s; int numtri = 0; if (r == NULL || m == NULL) return -1; *r = NULL; NMG_CK_MODEL(m); RT_CK_DB_INTERNAL(ip); mb = (struct rt_metaball_internal *)ip->idb_ptr; RT_METABALL_CK_MAGIC(mb); rt_prep_timer(); /* since this geometry isn't necessarily prepped, we have to figure out the * finalstep and bounding box manually. */ for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head)) V_MIN(finalstep, mbpt->fldstr); finalstep /= (fastf_t)1e5; radius = rt_metaball_get_bounding_sphere(¢er, mb->threshold, mb); if(radius < 0) { /* no control points */ bu_log("Attempting to tesselate metaball with no control points"); return -1; } rt_metaball_bbox(ip, &min, &max, tol); /* TODO: get better sampling tolerance, unless this is "good enough" */ mtol = ttol->abs; V_MAX(mtol, ttol->rel * radius * 10); V_MAX(mtol, tol->dist); *r = nmg_mrsv(m); /* new empty nmg */ s = BU_LIST_FIRST(shell, &(*r)->s_hd); /* the incredibly naïve approach. Time could be cut in half by simply * caching 4 point values, more by actually marching or doing active * refinement. This is the simplest pattern for now. */ for (i = min[X]; i < max[X]; i += mtol) for (j = min[Y]; j < max[Y]; j += mtol) for (k = min[Z]; k < max[Z]; k += mtol) { point_t p[8]; int pv = 0; /* generate the vertex values */ #define MEH(c,di,dj,dk) VSET(p[c], i+di, j+dj, k+dk); pv |= rt_metaball_point_inside((const point_t *)&p[c], mb) << c; MEH(0, 0, 0, mtol); MEH(1, mtol, 0, mtol); MEH(2, mtol, 0, 0); MEH(3, 0, 0, 0); MEH(4, 0, mtol, mtol); MEH(5, mtol, mtol, mtol); MEH(6, mtol, mtol, 0); MEH(7, 0, mtol, 0); #undef MEH if ( pv != 0 && pv != 255 ) { /* entire cube is either inside or outside */ point_t edges[12]; int rval; /* compute the edge values (if needed) */ #define MEH(a,b,c) if(!(pv&(1<<b)&&pv&(1<<c))) { \ rt_metaball_find_intersection(edges+a, mb, (const point_t *)(p+b), (const point_t *)(p+c), mtol, finalstep); \ } /* magic numbers! an edge, then the two attached vertices. * For edge/vertex mapping, refer to the awesome ascii art * at the beginning of this file. */ MEH(0 ,0,1); MEH(1 ,1,2); MEH(2 ,2,3); MEH(3 ,0,3); MEH(4 ,4,5); MEH(5 ,5,6); MEH(6 ,6,7); MEH(7 ,4,7); MEH(8 ,0,4); MEH(9 ,1,5); MEH(10,2,6); MEH(11,3,7); #undef MEH rval = nmg_mc_realize_cube(s, pv, (point_t *)edges, tol); numtri += rval; if(rval < 0) { bu_log("Error attempting to realize a cube O.o\n"); return rval; } } } nmg_mark_edges_real(&s->l.magic); nmg_region_a(*r, tol); nmg_model_fuse(m, tol); rt_get_timer(×, NULL); bu_log("metaball tesselate (%d triangles): %s\n", numtri, bu_vls_addr(×)); return 0; }