/* * Call parse_args to handle command line arguments first, then * process input. */ int main(int ac, char *av[]) { struct bn_tol tol; FILE *fdplot; struct rt_wdb *fdmodel; parse_args(ac, av); if (ac==1) usage((char *)NULL,0); if (!manifold[0] && !manifold[1] && !manifold[2] && !manifold[3]) usage("No manifolds selected\n",1); m = nmg_mm(); r = nmg_mrsv(m); s = BU_LIST_FIRST(shell, &r->s_hd); tol.magic = BN_TOL_MAGIC; tol.dist = 0.01; tol.dist_sq = tol.dist * tol.dist; tol.perp = 0.001; tol.para = 0.999; if (manifold[3]) make_3manifold_bits(&tol); if (manifold[2]) make_2manifold_bits(&tol); if (manifold[1]) make_1manifold_bits(); if (manifold[0]) make_0manifold_bits(); NMG_CK_MODEL(m); /* write a plot file */ if ((fdplot = fopen(plotfilename, "w")) == (FILE *)NULL) perror(plotfilename); else { nmg_pl_m(fdplot, m); fclose(fdplot); } /* write the database */ if ((fdmodel = wdb_fopen(mfilename)) == NULL) perror(mfilename); else { mk_id(fdmodel, "hairy NMG"); mk_nmg(fdmodel, "s.NMG", m); /* releases m, boo */ /* build a database region mentioning the solid */ mk_comb1(fdmodel, "r.NMG", "s.NMG", 1); wdb_close(fdmodel); } return 0; }
/* * Convert an ascii nmg description into a BRL-CAD data base. */ static int ascii_to_brlcad(FILE *fpin, struct rt_wdb *fpout, char *reg_name, char *grp_name) { struct model *m; struct nmgregion *r; struct bn_tol tol; struct shell *s; vect_t Ext; struct faceuse *fu; plane_t pl; VSETALL(Ext, 0.); m = nmg_mm(); /* Make nmg model. */ r = nmg_mrsv(m); /* Make region, empty shell, vertex */ s = BU_LIST_FIRST(shell, &r->s_hd); descr_to_nmg(s, fpin, Ext); /* Convert ascii description to nmg. */ /* Copied from proc-db/nmgmodel.c */ tol.magic = BN_TOL_MAGIC; tol.dist = 0.01; tol.dist_sq = tol.dist * tol.dist; tol.perp = 0.001; tol.para = 0.999; /* Associate the face geometry. */ fu = BU_LIST_FIRST( faceuse, &s->fu_hd ); if (nmg_loop_plane_area(BU_LIST_FIRST(loopuse, &fu->lu_hd), pl) < 0.0) return -1; else nmg_face_g( fu, pl ); if (!NEAR_ZERO(MAGNITUDE(Ext), 0.001)) nmg_extrude_face(BU_LIST_FIRST(faceuse, &s->fu_hd), Ext, &tol); nmg_region_a(r, &tol); /* Calculate geometry for region and shell. */ nmg_fix_normals( s, &tol ); /* insure that faces have outward pointing normals */ create_brlcad_db(fpout, m, reg_name, grp_name); return 0; }
/** * R T _ P G _ T E S S */ int rt_pg_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *tol) { size_t i; struct shell *s; struct vertex **verts; /* dynamic array of pointers */ struct vertex ***vertp;/* dynamic array of ptrs to pointers */ struct faceuse *fu; size_t p; /* current polygon number */ struct rt_pg_internal *pgp; RT_CK_DB_INTERNAL(ip); pgp = (struct rt_pg_internal *)ip->idb_ptr; RT_PG_CK_MAGIC(pgp); *r = nmg_mrsv(m); /* Make region, empty shell, vertex */ s = BU_LIST_FIRST(shell, &(*r)->s_hd); verts = (struct vertex **)bu_malloc( pgp->max_npts * sizeof(struct vertex *), "pg_tess verts[]"); vertp = (struct vertex ***)bu_malloc( pgp->max_npts * sizeof(struct vertex **), "pg_tess vertp[]"); for (i=0; i < pgp->max_npts; i++) vertp[i] = &verts[i]; for (p = 0; p < pgp->npoly; p++) { struct rt_pg_face_internal *pp; pp = &pgp->poly[p]; /* Locate these points, if previously mentioned */ for (i=0; i < pp->npts; i++) { verts[i] = nmg_find_pt_in_shell(s, &pp->verts[3*i], tol); } /* Construct the face. Verts should be in CCW order */ if ((fu = nmg_cmface(s, vertp, pp->npts)) == (struct faceuse *)0) { bu_log("rt_pg_tess() nmg_cmface failed, skipping face %zu\n", p); } /* Associate vertex geometry, where none existed before */ for (i=0; i < pp->npts; i++) { if (verts[i]->vg_p) continue; nmg_vertex_gv(verts[i], &pp->verts[3*i]); } /* Associate face geometry */ if (nmg_calc_face_g(fu)) { nmg_pr_fu_briefly(fu, ""); bu_free((char *)verts, "pg_tess verts[]"); bu_free((char *)vertp, "pg_tess vertp[]"); return -1; /* FAIL */ } } /* Compute "geometry" for region and shell */ nmg_region_a(*r, tol); /* Polysolids are often built with incorrect face normals. * Don't depend on them here. */ nmg_fix_normals(s, tol); bu_free((char *)verts, "pg_tess verts[]"); bu_free((char *)vertp, "pg_tess vertp[]"); return 0; /* OK */ }
int main(int argc, char **argv) /* really has no arguments */ { struct nmgregion *r; char * id_name = "BRL-CAD t-NURBS NMG Example"; char * tea_name = "UtahTeapot"; char * uplot_name = "teapot.pl"; struct bu_list vhead; FILE *fp; int i; tol.magic = BN_TOL_MAGIC; tol.dist = 0.005; tol.dist_sq = tol.dist * tol.dist; tol.perp = 1e-6; tol.para = 1 - tol.perp; BU_LIST_INIT( &rt_g.rtg_vlfree ); outfp = wdb_fopen( "tea_nmg.g" ); rt_g.debug |= DEBUG_ALLRAYS; /* Cause core dumps on bu_bomb(), but no extra messages */ while ((i=bu_getopt(argc, argv, "d")) != EOF) { switch (i) { case 'd' : rt_g.debug |= DEBUG_MEM | DEBUG_MEM_FULL; break; default : (void)fprintf(stderr, "Usage: %s [-d] > database.g\n", *argv); return(-1); } } mk_id( outfp, id_name); m = nmg_mm(); NMG_CK_MODEL( m ); r = nmg_mrsv( m ); NMG_CK_REGION( r ); s = BU_LIST_FIRST( shell, &r->s_hd ); NMG_CK_SHELL( s ); /* Step through each patch and create a NMG TNURB face * representing the patch then dump them out. */ for ( i = 0; i < PATCH_COUNT; i++) { dump_patch( patches[i] ); } /* Connect up the coincident vertexuses and edges */ (void)nmg_model_fuse( m, &tol ); /* write NMG to output file */ (void)mk_nmg( outfp, tea_name, m ); wdb_close(outfp); /* Make a vlist drawing of the model */ BU_LIST_INIT( &vhead ); nmg_m_to_vlist( &vhead, m, 0 ); /* Make a UNIX plot file from this vlist */ if ( (fp=fopen( uplot_name, "w" )) == NULL ) { bu_log( "Cannot open plot file: %s\n", uplot_name ); perror( "teapot_nmg" ); } else rt_vlist_to_uplot( fp, &vhead ); return(0); }
/** * 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; }
int psurf_to_nmg(struct model *m, FILE *fp, char *jfile) /* Input/output, nmg model. */ /* Input, pointer to psurf data file. */ /* Name of Jack data base file. */ { int face, fail, i, lst[MAX_NUM_PTS], nf, nv; struct faceuse *outfaceuses[MAX_NUM_PTS]; struct nmgregion *r; struct shell *s; struct vertex *vertlist[MAX_NUM_PTS]; struct vlist vert; /* Copied from proc-db/nmgmodel.c */ tol.magic = BN_TOL_MAGIC; tol.dist = 0.01; tol.dist_sq = tol.dist * tol.dist; tol.perp = 0.001; tol.para = 0.999; face = 0; r = nmg_mrsv(m); /* Make region, empty shell, vertex. */ s = BU_LIST_FIRST(shell, &r->s_hd); while ((nv = read_psurf_vertices(fp, &vert)) != 0) { size_t ret; while ((nf = read_psurf_face(fp, lst)) != 0) { /* Make face out of vertices in lst (ccw ordered). */ for (i = 0; i < nf; i++) vertlist[i] = vert.vt[lst[i]-1]; outfaceuses[face] = nmg_cface(s, vertlist, nf); face++; /* Save (possibly) newly created vertex structs. */ for (i = 0; i < nf; i++) vert.vt[lst[i]-1] = vertlist[i]; } ret = fscanf(fp, ";;"); if (ret > 0) bu_log("unknown parsing error\n"); /* Associate the vertex geometry, ccw. */ for (i = 0; i < nv; i++) if (vert.vt[i]) nmg_vertex_gv(vert.vt[i], &vert.pt[3*i]); else fprintf(stderr, "%s, vertex %d is unused\n", jfile, i+1); } nmg_vertex_fuse(&m->magic, &tol); /* Associate the face geometry. */ for (i = 0, fail = 0; i < face; i++) { struct loopuse *lu; plane_t pl; lu = BU_LIST_FIRST(loopuse, &outfaceuses[i]->lu_hd); if (nmg_loop_plane_area(lu, pl) < 0.0) { fail = 1; nmg_kfu(outfaceuses[i]); } else nmg_face_g(outfaceuses[i], pl); } if (fail) return -1; if (face) { int empty_model; empty_model = nmg_kill_zero_length_edgeuses(m); if (!empty_model) { /* Compute "geometry" for region and shell */ nmg_region_a(r, &tol); nmg_break_e_on_v(&m->magic, &tol); empty_model = nmg_kill_zero_length_edgeuses(m); /* Glue edges of outward pointing face uses together. */ if (!empty_model) nmg_edge_fuse(&m->magic, &tol); } } return 0; }
int extrude(int entityno) { fastf_t length; /* extrusion length */ vect_t edir; /* a unit vector (direction of extrusion */ vect_t evect; /* Scaled vector for extrusion */ int sol_num; /* IGES solid type number */ int curve; /* pointer to directory entry for base curve */ struct ptlist *curv_pts; /* List of points along curve */ int i; /* Default values */ VSET(edir, 0.0, 0.0, 1.0); /* Acquiring Data */ if (dir[entityno]->param <= pstart) { bu_log("Illegal parameter pointer for entity D%07d (%s)\n" , dir[entityno]->direct, dir[entityno]->name); return 0; } Readrec(dir[entityno]->param); Readint(&sol_num, ""); /* Read pointer to directory entry for curve to be extruded */ Readint(&curve, ""); /* Convert this to a "dir" index */ curve = (curve-1)/2; Readcnv(&length, ""); Readflt(&edir[X], ""); Readflt(&edir[Y], ""); Readflt(&edir[Z], ""); if (length <= 0.0) { bu_log("Illegal parameters for entity D%07d (%s)\n" , dir[entityno]->direct, dir[entityno]->name); return 0; } /* * Unitize direction vector */ VUNITIZE(edir); /* Scale vector */ VSCALE(evect, edir, length); /* Switch based on type of curve to be extruded */ switch (dir[curve]->type) { case 100: /* circular arc */ return Extrudcirc(entityno, curve, evect); case 104: /* conic arc */ return Extrudcon(entityno, curve, evect); case 102: /* composite curve */ case 106: /* copius data */ case 112: /* parametric spline */ case 126: { /* B-spline */ int npts; struct model *m; struct nmgregion *r; struct shell *s; struct faceuse *fu; struct loopuse *lu; struct edgeuse *eu; struct ptlist *pt_ptr; npts = Getcurve(curve, &curv_pts); if (npts < 3) return 0; m = nmg_mm(); r = nmg_mrsv(m); s = BU_LIST_FIRST(shell, &r->s_hd); fu = nmg_cface(s, (struct vertex **)NULL, npts-1); pt_ptr = curv_pts; lu = BU_LIST_FIRST(loopuse, &fu->lu_hd); for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) { struct vertex *v; v = eu->vu_p->v_p; nmg_vertex_gv(v, pt_ptr->pt); pt_ptr = pt_ptr->next; } if (nmg_calc_face_g(fu)) { bu_log("Extrude: Failed to calculate face geometry\n"); nmg_km(m); bu_free((char *)curv_pts, "curve_pts"); return 0; } if (nmg_extrude_face(fu, evect, &tol)) { bu_log("Extrude: extrusion failed\n"); nmg_km(m); bu_free((char *)curv_pts, "curve_pts"); return 0; } mk_bot_from_nmg(fdout, dir[entityno]->name, s); nmg_km(m); bu_free((char *)curv_pts, "curve_pts"); return 1; } default: i = (-1); while (dir[curve]->type != typecount[++i].type && i < ntypes); bu_log("Extrusions of %s are not allowed\n", typecount[i].name); break; } return 0; }
union tree * gcv_region_end_mc(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *client_data) { union tree *tp = NULL; struct model *m = NULL; struct nmgregion *r = NULL; struct shell *s = NULL; struct bu_list vhead; int empty_region = 0; int empty_model = 0; int NMG_debug_state = 0; int count = 0; void (*write_region)(struct nmgregion *, const struct db_full_path *, int, int, float [3]); if (!tsp || !pathp || !client_data) { bu_log("INTERNAL ERROR: gcv_region_end_mc missing parameters\n"); return TREE_NULL; } write_region = ((struct gcv_data *)client_data)->func; if (!write_region) { bu_log("INTERNAL ERROR: gcv_region_end missing conversion callback function\n"); return TREE_NULL; } RT_CK_FULL_PATH(pathp); RT_CK_TREE(curtree); RT_CK_TESS_TOL(tsp->ts_ttol); BN_CK_TOL(tsp->ts_tol); NMG_CK_MODEL(*tsp->ts_m); BU_LIST_INIT(&vhead); /* if (curtree->tr_op == OP_NOP) return 0; */ /* get a copy to play with as the parameters might get clobbered * by a longjmp. FIXME: db_dup_subtree() doesn't create real copies */ tp = db_dup_subtree(curtree, &rt_uniresource); /* FIXME: we can't free curtree until we get a "real" copy form * db_dup_subtree(). right now we get a fake copy just so we can * keep the compiler quiet about clobbering curtree during longjmp */ /* db_free_tree(curtree, &rt_uniresource); */ /* Sometimes the NMG library adds debugging bits when it detects * an internal error, before bombing. Stash. */ NMG_debug_state = RTG.NMG_debug; m = nmg_mmr(); r = nmg_mrsv(m); s = BU_LIST_FIRST(shell, &r->s_hd); if (tsp->ts_rtip == NULL) tsp->ts_rtip = rt_new_rti(tsp->ts_dbip); count += nmg_mc_evaluate (s, tsp->ts_rtip, pathp, tsp->ts_ttol, tsp->ts_tol); /* empty region? */ if (count == 0) { bu_log("Region %s appears to be empty.\n", db_path_to_string(pathp)); return TREE_NULL; } /* bu_log("Target is shot, %d triangles seen.\n", count); bu_log("Fusing\n"); fflush(stdout); nmg_model_fuse(m, tsp->ts_tol); bu_log("Done\n"); fflush(stdout); */ /* Kill cracks */ while (BU_LIST_NOT_HEAD(&s->l, &r->s_hd)) { struct shell *next_s; next_s = BU_LIST_PNEXT(shell, &s->l); if (nmg_kill_cracks(s)) { if (nmg_ks(s)) { empty_region = 1; break; } } /* nmg_shell_coplanar_face_merge(s, tsp->ts_tol, 42); */ s = next_s; } if (empty_region) return _gcv_cleanup(NMG_debug_state, tp); /* kill zero length edgeuses */ empty_model = nmg_kill_zero_length_edgeuses(*tsp->ts_m); if (empty_model) return _gcv_cleanup(NMG_debug_state, tp); if (BU_SETJUMP) { /* Error, bail out */ char *sofar; /* Relinquish bomb protection */ BU_UNSETJUMP; sofar = db_path_to_string(pathp); bu_log("FAILED in triangulator: %s\n", sofar); bu_free((char *)sofar, "sofar"); /* Release any intersector 2d tables */ nmg_isect2d_final_cleanup(); /* Get rid of (m)any other intermediate structures */ if ((*tsp->ts_m)->magic == NMG_MODEL_MAGIC) nmg_km(*tsp->ts_m); else bu_log("WARNING: tsp->ts_m pointer corrupted, ignoring it.\n"); /* Now, make a new, clean model structure for next pass. */ *tsp->ts_m = nmg_mm(); nmg_kr(r); return _gcv_cleanup(NMG_debug_state, tp); } else { /* Write the region out */ write_region(r, pathp, tsp->ts_regionid, tsp->ts_gmater, tsp->ts_mater.ma_color); } BU_UNSETJUMP; /* Relinquish bomb protection */ nmg_kr(r); return _gcv_cleanup(NMG_debug_state, tp); }
int read_faces(struct model *m, FILE *fgeom) { int nverts, nfaces, nedges; int i, j, fail=0; fastf_t *pts; struct vertex **verts; struct faceuse **outfaceuses; struct nmgregion *r; struct shell *s; size_t ret; /* Get numbers of vertices and faces, and grab the appropriate amount of memory */ if (fscanf(fgeom, "%d %d %d", &nverts, &nfaces, &nedges) != 3) bu_exit(1, "Cannot read number of vertices, faces, edges.\n"); pts = (fastf_t *) bu_malloc(sizeof(fastf_t) * 3 * nverts, "points list"); verts = (struct vertex **) bu_malloc(sizeof(struct vertex *) * nverts, "vertices"); outfaceuses = (struct faceuse **) bu_malloc(sizeof(struct faceuse *) * nfaces, "faceuses"); /* Read in vertex geometry, store in geometry list */ for (i = 0; i < nverts; i++) { double scan[3]; if (fscanf(fgeom, "%lf %lf %lf", &scan[0], &scan[1], &scan[2]) != 3) { bu_exit(1, "Not enough data points in geometry file.\n"); } pts[3*i] = scan[0]; pts[3*i+1] = scan[1]; pts[3*i+2] = scan[2]; verts[i] = (struct vertex *) 0; ret = fscanf(fgeom, "%*[^\n]"); if (ret > 0) bu_log("unknown parsing error\n"); } r = nmg_mrsv(m); /* Make region, empty shell, vertex. */ s = BU_LIST_FIRST(shell, &r->s_hd); for (i = 0; i < nfaces; i++) { /* Read in each of the faces */ struct vertex **vlist; int *pinds; if (fscanf(fgeom, "%d", &nedges) != 1) { bu_exit(1, "Not enough faces in geometry file.\n"); } /* Grab memory for list for this face. */ vlist = (struct vertex **) bu_malloc(sizeof(struct vertex *) * nedges, "vertex list"); pinds = (int *) bu_malloc(sizeof(int) * nedges, "point indices"); for (j = 0; j < nedges; j++) { /* Read list of point indices. */ if (fscanf(fgeom, "%d", &pinds[j]) != 1) { bu_exit(1, "Not enough points on face.\n"); } vlist[j] = verts[pinds[j]-1]; } outfaceuses[i] = nmg_cface(s, vlist, nedges); /* Create face. */ NMG_CK_FACEUSE(outfaceuses[i]); for (j = 0; j < nedges; j++) /* Save (possibly) newly created vertex structs. */ verts[pinds[j]-1] = vlist[j]; ret = fscanf(fgeom, "%*[^\n]"); if (ret > 0) bu_log("unknown parsing error\n"); bu_free((char *)vlist, "vertext list"); bu_free((char *)pinds, "point indices"); } for (i = 0; i < nverts; i++) if (verts[i] != 0) nmg_vertex_gv(verts[i], &pts[3*i]); else fprintf(stderr, "Warning: vertex %d unused.\n", i+1); for (i = 0; i < nfaces; i++) { plane_t pl; fprintf(stderr, "planeeqning face %d.\n", i); if ( nmg_loop_plane_area( BU_LIST_FIRST( loopuse, &outfaceuses[i]->lu_hd ), pl ) < 0.0 ) fail = 1; else nmg_face_g( outfaceuses[i], pl ); } if (fail) return -1; nmg_gluefaces(outfaceuses, nfaces, &tol); nmg_region_a(r, &tol); bu_free((char *)pts, "points list"); return 0; }
HIDDEN void get_ctria3(void) { int pid; int g1, g2, g3; int gin1, gin2, gin3; point_t pt1, pt2, pt3; struct vertex **v[3]; struct faceuse *fu; struct shell *s; struct pshell *psh; int pid_index=0; pid = atoi(curr_rec[2]); pid_index = get_pid_index(pid); g1 = atoi(curr_rec[3]); g2 = atoi(curr_rec[4]); g3 = atoi(curr_rec[5]); gin1 = get_gridi(g1); gin2 = get_gridi(g2); gin3 = get_gridi(g3); v[0] = &g_pts[gin1].v[pid_index]; v[1] = &g_pts[gin2].v[pid_index]; v[2] = &g_pts[gin3].v[pid_index]; VSCALE(pt1, g_pts[gin1].pt, conv[units]); VSCALE(pt2, g_pts[gin2].pt, conv[units]); VSCALE(pt3, g_pts[gin3].pt, conv[units]); if (!nmg_model && !pid) { struct nmgregion *r; nmg_model = nmg_mm(); r = nmg_mrsv(nmg_model); nmg_shell = BU_LIST_FIRST(shell, &r->s_hd); } if (!pid) s = nmg_shell; else { int found=0; /* find pshell entry for this pid */ for (BU_LIST_FOR(psh, pshell, &pshell_head.l)) { if (psh->pid == pid) { found = 1; break; } } if (!found) { bu_log("Cannot find PSHELL entry for a CTRIA3 element (ignoring)!\n"); write_fields(); return; } if (psh->s) s = psh->s; else { struct model *m; struct nmgregion *r; m = nmg_mm(); r = nmg_mrsv(m); s = BU_LIST_FIRST(shell, &r->s_hd); psh->s = s; } } fu = nmg_cmface(s, v, 3); if (!g_pts[gin1].v[pid_index]->vg_p) nmg_vertex_gv(g_pts[gin1].v[pid_index], pt1); if (!g_pts[gin2].v[pid_index]->vg_p) nmg_vertex_gv(g_pts[gin2].v[pid_index], pt2); if (!g_pts[gin3].v[pid_index]->vg_p) nmg_vertex_gv(g_pts[gin3].v[pid_index], pt3); nmg_calc_face_g(fu); }
/** * "Tessellate" an ARB into an NMG data structure. * Purely a mechanical transformation of one faceted object * into another. * * Returns - * -1 failure * 0 OK. *r points to nmgregion that holds this tessellation. */ int rt_arbn_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *tol) { struct rt_arbn_internal *aip; struct shell *s; struct faceuse **fu; /* array of faceuses */ size_t nverts; /* maximum possible number of vertices = neqn!/(3!(neqn-3)! */ size_t point_count = 0; /* actual number of vertices */ size_t face_count = 0; /* actual number of faces built */ size_t i, j, k, l, n; struct arbn_pts *pts; struct arbn_edges *edges; /* A list of edges for each plane eqn (each face) */ size_t *edge_count; /* number of edges for each face */ size_t max_edge_count; /* maximum number of edges for any face */ struct vertex **verts; /* Array of pointers to vertex structs */ struct vertex ***loop_verts; /* Array of pointers to vertex structs to pass to nmg_cmface */ RT_CK_DB_INTERNAL(ip); aip = (struct rt_arbn_internal *)ip->idb_ptr; RT_ARBN_CK_MAGIC(aip); /* Allocate memory for the vertices */ nverts = aip->neqn * (aip->neqn-1) * (aip->neqn-2) / 6; pts = (struct arbn_pts *)bu_calloc(nverts, sizeof(struct arbn_pts), "rt_arbn_tess: pts"); /* Allocate memory for arbn_edges */ edges = (struct arbn_edges *)bu_calloc(aip->neqn*aip->neqn, sizeof(struct arbn_edges) , "rt_arbn_tess: edges"); edge_count = (size_t *)bu_calloc(aip->neqn, sizeof(size_t), "rt_arbn_tess: edge_count"); /* Allocate memory for faceuses */ fu = (struct faceuse **)bu_calloc(aip->neqn, sizeof(struct faceuse *), "rt_arbn_tess: fu"); /* Calculate all vertices */ for (i = 0; i < aip->neqn; i++) { for (j = i + 1; j < aip->neqn; j++) { for (k = j + 1; k < aip->neqn; k++) { int keep_point = 1; if (bn_mkpoint_3planes(pts[point_count].pt, aip->eqn[i], aip->eqn[j], aip->eqn[k])) continue; for (l = 0; l < aip->neqn; l++) { if (l == i || l == j || l == k) continue; if (DIST_PT_PLANE(pts[point_count].pt, aip->eqn[l]) > tol->dist) { keep_point = 0; break; } } if (keep_point) { pts[point_count].plane_no[0] = i; pts[point_count].plane_no[1] = j; pts[point_count].plane_no[2] = k; point_count++; } } } } /* Allocate memory for the NMG vertex pointers */ verts = (struct vertex **)bu_calloc(point_count, sizeof(struct vertex *) , "rt_arbn_tess: verts"); /* Associate points with vertices */ for (i = 0; i < point_count; i++) pts[i].vp = &verts[i]; /* Check for duplicate points */ for (i = 0; i < point_count; i++) { for (j = i + 1; j < point_count; j++) { if (DIST_PT_PT_SQ(pts[i].pt, pts[j].pt) < tol->dist_sq) { /* These two points should point to the same vertex */ pts[j].vp = pts[i].vp; } } } /* Make list of edges for each face */ for (i = 0; i < aip->neqn; i++) { /* look for a point that lies in this face */ for (j = 0; j < point_count; j++) { if (pts[j].plane_no[0] != (int)i && pts[j].plane_no[1] != (int)i && pts[j].plane_no[2] != (int)i) continue; /* look for another point that shares plane "i" and another with this one */ for (k = j + 1; k < point_count; k++) { size_t match = (size_t)-1; size_t pt1, pt2; int duplicate = 0; /* skip points not on plane "i" */ if (pts[k].plane_no[0] != (int)i && pts[k].plane_no[1] != (int)i && pts[k].plane_no[2] != (int)i) continue; for (l = 0; l < 3; l++) { for (n = 0; n < 3; n++) { if (pts[j].plane_no[l] == pts[k].plane_no[n] && pts[j].plane_no[l] != (int)i) { match = pts[j].plane_no[l]; break; } } if (match != (size_t)-1) break; } if (match == (size_t)-1) continue; /* convert equivalent points to lowest point number */ pt1 = j; pt2 = k; for (l = 0; l < pt1; l++) { if (pts[pt1].vp == pts[l].vp) { pt1 = l; break; } } for (l = 0; l < pt2; l++) { if (pts[pt2].vp == pts[l].vp) { pt2 = l; break; } } /* skip null edges */ if (pt1 == pt2) continue; /* check for duplicate edge */ for (l = 0; l < edge_count[i]; l++) { if ((edges[LOC(i, l)].v1_no == (int)pt1 && edges[LOC(i, l)].v2_no == (int)pt2) || (edges[LOC(i, l)].v2_no == (int)pt1 && edges[LOC(i, l)].v1_no == (int)pt2)) { duplicate = 1; break; } } if (duplicate) continue; /* found an edge belonging to faces "i" and "match" */ if (edge_count[i] == aip->neqn) { bu_log("Too many edges found for one face\n"); goto fail; } edges[LOC(i, edge_count[i])].v1_no = pt1; edges[LOC(i, edge_count[i])].v2_no = pt2; edge_count[i]++; } } } /* for each face, sort the list of edges into a loop */ Sort_edges(edges, edge_count, aip); /* Get max number of edges for any face */ max_edge_count = 0; for (i = 0; i < aip->neqn; i++) if (edge_count[i] > max_edge_count) max_edge_count = edge_count[i]; /* Allocate memory for array to pass to nmg_cmface */ loop_verts = (struct vertex ***) bu_calloc(max_edge_count, sizeof(struct vertex **) , "rt_arbn_tess: loop_verts"); *r = nmg_mrsv(m); /* Make region, empty shell, vertex */ s = BU_LIST_FIRST(shell, &(*r)->s_hd); /* Make the faces */ for (i = 0; i < aip->neqn; i++) { int loop_length = 0; for (j = 0; j < edge_count[i]; j++) { /* skip zero length edges */ if (pts[edges[LOC(i, j)].v1_no].vp == pts[edges[LOC(i, j)].v2_no].vp) continue; /* put vertex pointers into loop_verts array */ loop_verts[loop_length] = pts[edges[LOC(i, j)].v2_no].vp; loop_length++; } /* Make the face if there is are least 3 vertices */ if (loop_length > 2) fu[face_count++] = nmg_cmface(s, loop_verts, loop_length); } /* Associate vertex geometry */ for (i = 0; i < point_count; i++) { if (!(*pts[i].vp)) continue; if ((*pts[i].vp)->vg_p) continue; nmg_vertex_gv(*pts[i].vp, pts[i].pt); } bu_free((char *)pts, "rt_arbn_tess: pts"); bu_free((char *)edges, "rt_arbn_tess: edges"); bu_free((char *)edge_count, "rt_arbn_tess: edge_count"); bu_free((char *)verts, "rt_arbn_tess: verts"); bu_free((char *)loop_verts, "rt_arbn_tess: loop_verts"); /* Associate face geometry */ for (i = 0; i < face_count; i++) { if (nmg_fu_planeeqn(fu[i], tol)) { bu_log("Failed to calculate face plane equation\n"); bu_free((char *)fu, "rt_arbn_tess: fu"); nmg_kr(*r); *r = (struct nmgregion *)NULL; return -1; } } bu_free((char *)fu, "rt_arbn_tess: fu"); nmg_fix_normals(s, tol); (void)nmg_mark_edges_real(&s->l.magic); /* Compute "geometry" for region and shell */ nmg_region_a(*r, tol); return 0; fail: bu_free((char *)pts, "rt_arbn_tess: pts"); bu_free((char *)edges, "rt_arbn_tess: edges"); bu_free((char *)edge_count, "rt_arbn_tess: edge_count"); bu_free((char *)verts, "rt_arbn_tess: verts"); return -1; }