/* * Write the nmg to a BRL-CAD style data base. */ int create_brlcad_db(struct rt_wdb *fpout, struct model *m, char *reg_name, char *grp_name) { char *rname, *sname; int empty_model; struct shell *s; struct nmgregion *r; rname = (char *)bu_malloc(sizeof(reg_name) + 3, "rname"); /* Region name. */ sname = (char *)bu_malloc(sizeof(reg_name) + 3, "sname"); /* Solid name. */ snprintf(sname, sizeof(reg_name) + 2, "s.%s", reg_name); empty_model = nmg_kill_zero_length_edgeuses(m); if (empty_model) { bu_log("Warning: skipping empty model."); return 0; } nmg_rebound(m, &tol); r = BU_LIST_FIRST(nmgregion, &m->r_hd); s = BU_LIST_FIRST(shell, &r->s_hd); mk_bot_from_nmg(fpout, sname, s); /* Make BOT object. */ snprintf(rname, sizeof(reg_name) + 2, "r.%s", reg_name); mk_comb1(fpout, rname, sname, 1); /* Put object in a region. */ if (grp_name) { mk_comb1(fpout, grp_name, rname, 1); /* Region in group. */ } return 0; }
static void nmg_conv(struct rt_db_internal *intern, const char *name) { struct model *m; struct nmgregion *r; struct shell *s; RT_CK_DB_INTERNAL(intern); m = (struct model *)intern->idb_ptr; NMG_CK_MODEL(m); r = BU_LIST_FIRST(nmgregion, &m->r_hd); if (r && BU_LIST_NEXT(nmgregion, &r->l) != (struct nmgregion *)&m->r_hd) bu_exit(1, "ERROR: this code works only for NMG models with one region!\n"); s = BU_LIST_FIRST(shell, &r->s_hd); if (s && BU_LIST_NEXT(shell, &s->l) != (struct shell *)&r->s_hd) bu_exit(1, "ERROR: this code works only for NMG models with one shell!\n"); if (!s) { bu_log("WARNING: NMG has no shells\n"); return; } if (!BU_SETJUMP) { /* try */ mk_bot_from_nmg(fdout, name, s); } else { /* catch */ BU_UNSETJUMP; bu_log("Failed to convert %s\n", name); return; } BU_UNSETJUMP; if (verbose) bu_log("Converted %s to a Bot solid\n", name); }
/** * Stub function which will "simulate" a call to a vector shot routine */ HIDDEN void vshot_stub(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap) /* An array of solid pointers */ /* An array of ray pointers */ /* array of segs (results returned) */ /* Number of ray/object pairs */ /* pointer to an application */ { register int i; register struct seg *tmp_seg; struct seg seghead; int ret; BU_LIST_INIT(&(seghead.l)); /* go through each ray/solid pair and call a scalar function */ for (i = 0; i < n; i++) { if (stp[i] != 0) { /* skip call if solid table pointer is NULL */ /* do scalar call, place results in segp array */ ret = -1; if (OBJ[stp[i]->st_id].ft_shot) { ret = OBJ[stp[i]->st_id].ft_shot(stp[i], rp[i], ap, &seghead); } if (ret <= 0) { segp[i].seg_stp=(struct soltab *) 0; } else { tmp_seg = BU_LIST_FIRST(seg, &(seghead.l)); BU_LIST_DEQUEUE(&(tmp_seg->l)); segp[i] = *tmp_seg; /* structure copy */ RT_FREE_SEG(tmp_seg, ap->a_resource); } } } }
/* * 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; }
void bu_free_mapped_files(int verbose) { struct bu_mapped_file *mp, *next; if (UNLIKELY(bu_debug&BU_DEBUG_MAPPED_FILE)) bu_log("bu_free_mapped_files(verbose=%d)\n", verbose); bu_semaphore_acquire(BU_SEM_MAPPEDFILE); next = BU_LIST_FIRST(bu_mapped_file, &bu_mapped_file_list); while (BU_LIST_NOT_HEAD(next, &bu_mapped_file_list)) { BU_CK_MAPPED_FILE(next); mp = next; next = BU_LIST_NEXT(bu_mapped_file, &mp->l); if (mp->uses > 0) continue; /* Found one that needs to have storage released */ if (UNLIKELY(verbose || (bu_debug&BU_DEBUG_MAPPED_FILE))) bu_pr_mapped_file("freeing", mp); BU_LIST_DEQUEUE(&mp->l); /* If application pointed mp->apbuf at mp->buf, break that * association so we don't double-free the buffer. */ if (mp->apbuf == mp->buf) mp->apbuf = (void *)NULL; #ifdef HAVE_SYS_MMAN_H if (mp->is_mapped) { int ret; bu_semaphore_acquire(BU_SEM_SYSCALL); ret = munmap(mp->buf, (size_t)mp->buflen); bu_semaphore_release(BU_SEM_SYSCALL); if (UNLIKELY(ret < 0)) perror("munmap"); /* XXX How to get this chunk of address space back to malloc()? */ } else #endif { bu_free(mp->buf, "bu_mapped_file.buf[]"); } mp->buf = (void *)NULL; /* sanity */ bu_free((void *)mp->name, "bu_mapped_file.name"); if (mp->appl) bu_free((void *)mp->appl, "bu_mapped_file.appl"); bu_free((void *)mp, "struct bu_mapped_file"); } bu_semaphore_release(BU_SEM_MAPPEDFILE); }
/* * 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; }
HIDDEN void bu_log_call_hooks(genptr_t buf) { #if 0 bu_hook_t hookfunc; /* for clarity */ genptr_t clientdata; #endif bu_log_hooks_called = 1; #if 0 hookfunc = BU_LIST_FIRST(bu_hook_list, &(bu_log_hook_list.l))->hookfunc; clientdata = BU_LIST_FIRST(bu_hook_list, &(bu_log_hook_list.l))->clientdata; (hookfunc)( clientdata, buf); #else bu_call_hook(&bu_log_hook_list, buf); #endif bu_log_hooks_called = 0; }
void nmg_visit_loopuse(struct loopuse *lu, const struct nmg_visit_handlers *htab, void *state) /* Handler's private state */ { NMG_CK_LOOPUSE(lu); if (htab->bef_loopuse) htab->bef_loopuse((uint32_t *)lu, state, 0); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC) { struct vertexuse *vu; vu = BU_LIST_FIRST(vertexuse, &lu->down_hd); nmg_visit_vertexuse(vu, htab, state); } else { struct edgeuse *eu; for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) { nmg_visit_edgeuse(eu, htab, state); } } nmg_visit_loop(lu->l_p, htab, state); if (htab->aft_loopuse) htab->aft_loopuse((uint32_t *)lu, state, 1); }
int main(int argc, char **argv) { struct application ap; /* Structure passed between functions. */ struct rt_i *rtip; int idx; /* Index for rt_dirbuild & rt_gettree. */ char idbuf[32]; /* Contains database name. */ struct region *pr; /* Used in finding region names. */ double rho, phi, theta;/* Spherical coordinates for starting point. */ double areabs=0.0; /* Area of bounding sphere (mm**2). */ int ians; /* Answer of question. */ double strtpt[3]; /* Starting point of ray. */ double strtdir[3]; /* Starting direction. */ size_t loops; /* Number of rays fired. */ size_t r; /* Variable in loops. */ int i, j, k; /* Variable in loops. */ long seed; /* Initial seed for random number generator. */ double denom; /* Denominator. */ double elev; /* Elevation, used to find point on yz-plane. */ double az; /* Azimuth, used to find point on yz-plane. */ double rad; /* Radius, used to find point on yz-plane. */ double s[3], t[3]; /* Temporary variables used to find points. */ double q; /* Temporary variable used to find points. */ int numreg; /* Number of regions. */ double center[3]; /* Center of the bounding rpp. */ double sf; /* Used to print shape factor. */ double dump; /* How often a dump is to occur. */ int idump; /* 1=>dump to occur. */ FILE *fp; /* Used to open files. */ char outfile[16]; /* Output file. */ FILE *fp1; /* Used to read region # & name file. */ char rnnfile[16]; /* Region # & name file. */ FILE *fp2; /* Used to write the error file. */ char errfile[16]; /* Error file. */ double totalsf; /* Sum of shape factors. */ double totalnh; /* Sum of number of hits. */ int itype; /* Type of file to be created, 0=>regular, */ /* 1=>generic. */ char line[500]; /* Buffer to read a line of data into. */ int c; /* Reads one character of information. */ int icnt; /* Counter for shape factor. */ char tmpname[150]; /* Temporary name. */ int tmpreg; /* Temporary region number. */ char rnnname[800][150]; /* Region name from region # & name file. */ int rnnnum; /* Number of regions in region # & name file. */ int rnnchar[800]; /* Number of characters in name. */ int rnnreg[800]; /* Region number from region # & name file. */ int jcnt; /* Counter. */ int equal; /* 0=>equal, 1=>not equal. */ double rcpi, rcpj; /* Used to check reciprocity. */ double rcp_diff; /* Difference in reciprocity. */ double rcp_pdiff; /* Percent difference in reciprocity. */ int ret; struct bn_unif *msr = NULL; /* Check to see if arguments are implemented correctly. */ if ((argc < 3 || argv[1] == NULL) || (argv[2] == NULL)) { fprintf(stderr, "\nUsage: %s file.g objects\n\n", *argv); } else { /* START # 1 */ /* Ask what type of file is to be created - regular */ /* or generic. */ printf("Enter type of file to be written (0=>regular or "); printf("1=>generic). "); (void)fflush(stdout); ret = scanf("%1d", &itype); if (ret == 0) bu_exit(-1, "scanf failure when reading file type"); if (itype != 1) itype = 0; /* Enter names of files to be used. */ fprintf(stderr, "Enter name of output file (15 char max).\n\t"); (void)fflush(stderr); ret = scanf("%15s", outfile); if (ret == 0) bu_exit(-1, "scanf failure when reading output file name"); /* Read name of the error file to be written. */ printf("Enter the name of the error file (15 char max).\n\t"); (void)fflush(stdout); ret = scanf("%15s", errfile); if (ret == 0) bu_exit(-1, "scanf failure when reading error file name"); { /* Enter name of region # & name file to be read. */ printf("Enter region # & name file to be read "); printf("(15 char max).\n\t"); (void)fflush(stdout); ret = scanf("%15s", rnnfile); if (ret == 0) bu_exit(-1, "scanf failure when reading region # + name file"); } /* Check if dump is to occur. */ idump = 0; printf("Do you want to dump intermediate shape factors to "); printf("screen (0-no, 1-yes)? "); (void)fflush(stdout); ret = scanf("%1d", &idump); if (ret == 0) bu_exit(-1, "scanf failure - intermediate shape factors setting"); /* Find number of rays to be fired. */ fprintf(stderr, "Enter number of rays to be fired. "); (void)fflush(stderr); ret = scanf("%llu", (unsigned long long *)&loops); if (ret == 0) bu_exit(-1, "scanf failure - number of rays to be fired"); /* clamp loops */ if (loops > UINT32_MAX) loops = UINT32_MAX; /* Set seed for random number generator. */ seed = 1; fprintf(stderr, "Do you wish to enter your own seed (0) or "); fprintf(stderr, "use the default of 1 (1)? "); (void)fflush(stderr); ret = scanf("%1d", &ians); if (ret == 0) bu_exit(-1, "scanf failure - seed use setting"); if (ians == 0) { fprintf(stderr, "Enter unsigned integer seed. "); (void)fflush(stderr); ret = scanf("%ld", &seed); if (ret == 0) bu_exit(-1, "scanf failure - seed"); } msr = bn_unif_init(seed, 0); bu_log("seed initialized\n"); /* Read region # & name file. */ rnnnum = 0; fp1 = fopen(rnnfile, "rb"); c = getc(fp1); while (c != EOF) { (void)ungetc(c, fp1); (void)bu_fgets(line, 200, fp1); sscanf(line, "%d%149s", &tmpreg, tmpname); for (i=0; i<150; i++) { rnnname[rnnnum][i] = tmpname[i]; } rnnreg[rnnnum] = tmpreg; rnnnum++; c = getc(fp1); } (void)fclose(fp1); printf("Number of regions read from region # & name file: %d\n", rnnnum); (void)fflush(stdout); /* Find number of characters in each region name. */ for (i=0; i<rnnnum; i++) { jcnt = 0; while (rnnname[i][jcnt] != '\0') { jcnt++; } rnnchar[i] = jcnt; } /* Build directory. */ idx = 1; /* Set index for rt_dirbuild. */ rtip = rt_dirbuild(argv[idx], idbuf, sizeof(idbuf)); printf("Database Title: %s\n", idbuf); (void)fflush(stdout); /* Set useair to 1 to show hits of air. */ rtip->useair = 1; /* Load desired objects. */ idx = 2; /* Set index. */ while (argv[idx] != NULL) { rt_gettree(rtip, argv[idx]); idx += 1; } /* Find number of regions. */ numreg = (int)rtip->nregions; fprintf(stderr, "Number of regions: %d\n", numreg); (void)fflush(stderr); /* Zero all arrays. */ for (i=0; i<numreg; i++) { info[i].name = "\0"; info[i].regnum = (-1); info[i].numchar = 0; info[i].lvrays = 0.0; info[i].engarea = 0.0; for (j=0; j<numreg; j++) { info[i].intrays[j] = 0.0; } } nummiss = 0.0; /* Get database ready by starting prep. */ rt_prep(rtip); /* Find the center of the bounding rpp. */ center[X] = rtip->mdl_min[X] + (rtip->mdl_max[X] - rtip->mdl_min[X]) / 2.0; center[Y] = rtip->mdl_min[Y] + (rtip->mdl_max[Y] - rtip->mdl_min[Y]) / 2.0; center[Z] = rtip->mdl_min[Z] + (rtip->mdl_max[Z] - rtip->mdl_min[Z]) / 2.0; /* Put region names into structure. */ pr = BU_LIST_FIRST(region, &rtip->HeadRegion); for (i=0; i<numreg; i++) { info[(int)(pr->reg_bit)].name = pr->reg_name; pr = BU_LIST_FORW(region, &(pr->l)); } /* Set up parameters for rt_shootray. */ RT_APPLICATION_INIT(&ap); ap.a_hit = hit; /* User supplied hit function. */ ap.a_miss = miss; /* User supplied miss function. */ ap.a_overlap = overlap; /* User supplied overlap function. */ ap.a_rt_i = rtip; /* Pointer from rt_dirbuild. */ ap.a_onehit = 0; /* Look at all hits. */ ap.a_level = 0; /* Recursion level for diagnostics. */ ap.a_resource = 0; /* Address for resource structure. */ dump = 1000000.0; /* Used for dumping info. */ for (r=0; r<loops; r++) { /* Number of rays fired. */ /* START # 2 */ /* Find length of 'diagonal' (rho). (In reality rho is */ /* the radius of bounding sphere). */ rho = (rtip->mdl_max[X] - rtip->mdl_min[X]) * (rtip->mdl_max[X] - rtip->mdl_min[X]) +(rtip->mdl_max[Y] - rtip->mdl_min[Y]) * (rtip->mdl_max[Y] - rtip->mdl_min[Y]) +(rtip->mdl_max[Z] - rtip->mdl_min[Z]) * (rtip->mdl_max[Z] - rtip->mdl_min[Z]); rho = sqrt(rho) / 2.0 + .5; /* find surface area of bounding sphere. */ areabs = 4.0 * M_PI * rho * rho; /* Second way to find starting point and direction. */ /* This approach finds the starting point and direction */ /* by using parallel rays. */ /* Find point on the bounding sphere. (The negative */ /* of the unit vector of this point will eventually be */ /* the firing direction. */ q = BN_UNIF_DOUBLE(msr) + 0.5; theta = q * M_2PI; q = BN_UNIF_DOUBLE(msr) + 0.5; phi = (q * 2.0) - 1.0; phi = acos(phi); strtdir[X] = rho * sin(phi) * cos(theta); strtdir[Y] = rho * sin(phi) * sin(theta); strtdir[Z] = rho * cos(phi); /* Elevation and azimuth for finding a vector in a plane. */ elev = M_PI_2 - phi; az = theta; /* Find vector in yz-plane. */ q = BN_UNIF_DOUBLE(msr) + 0.5; theta = q * M_2PI; q = BN_UNIF_DOUBLE(msr) + 0.5; rad = rho * sqrt(q); s[X] = 0.0; s[Y] = rad * cos(theta); s[Z] = rad * sin(theta); /* Rotate vector. */ t[X] = s[X] * cos(elev) * cos(az) - s[Z] * sin(elev) * cos(az) - s[Y] * sin(az); t[Y] = s[X] * cos(elev) * sin(az) - s[Z] * sin(elev) * sin(az) + s[Y] * cos(az); t[Z] = s[X] * sin(elev) + s[Z] * cos(elev); /* Translate the point. This is starting point. */ strtpt[X] = t[X] + strtdir[X]; strtpt[Y] = t[Y] + strtdir[Y]; strtpt[Z] = t[Z] + strtdir[Z]; /* Now transfer starting point so that it is in */ /* the absolute coordinates not the origin's. */ strtpt[X] += center[X]; strtpt[Y] += center[Y]; strtpt[Z] += center[Z]; /* Normalize starting direction and make negative. */ denom = strtdir[X] * strtdir[X] + strtdir[Y] * strtdir[Y] + strtdir[Z] * strtdir[Z]; denom = sqrt(denom); strtdir[X] /= (-denom); strtdir[Y] /= (-denom); strtdir[Z] /= (-denom); /* Set up firing point and direction. */ ap.a_ray.r_pt[X] = strtpt[X]; ap.a_ray.r_pt[Y] = strtpt[Y]; ap.a_ray.r_pt[Z] = strtpt[Z]; ap.a_ray.r_dir[X] = strtdir[X]; ap.a_ray.r_dir[Y] = strtdir[Y]; ap.a_ray.r_dir[Z] = strtdir[Z]; /* Call rt_shootray for "forward ray". */ (void)rt_shootray(&ap); if (EQUAL(r, (dump - 1.0))) { printf("%llu rays have been fired in forward direction.\n", (unsigned long long)(r+1)); (void)fflush(stdout); if (idump == 1) { /* START # 3 */ printf("\n****************************************"); printf("****************************************\n"); (void)fflush(stdout); /* Dump info to file. */ for (i=0; i<numreg; i++) { for (j=0; j<numreg; j++) { sf = 0.0; if ((info[i].lvrays < -ZEROTOL) || (ZEROTOL < info[i].lvrays)) sf = info[i].intrays[j] / info[i].lvrays; printf("%d\t%d\t%f\n", i, j, sf); (void)fflush(stdout); } } } /* START # 3 */ dump = dump + 1000000.0; } } /* END # 2 */ /* Find area bounded by engine air using Monte Carlo method. */ for (i=0; i<numreg; i++) { /* Old way, only incrementing info[i].allvrays for forward */ /* ray therefore do not divide by 2. Division by 2 is to */ /* include the backwards ray also. */ /* * info[i].engarea = info[i].allvrays * areabs / loops / 2.0; */ info[i].engarea = info[i].allvrays * areabs / (double)loops; /* Put area into square meters. */ info[i].engarea *= 1.e-6; } /* Find number of characters in each region name. */ for (i=0; i<numreg; i++) { jcnt = 0; while (info[i].name[jcnt] != '\0') { jcnt++; } info[i].numchar = jcnt; } /* Find correct region number. */ printf("Finding correct region numbers.\n"); (void)fflush(stdout); for (i=0; i<numreg; i++) { for (j=0; j<rnnnum; j++) { equal = 0; /* 1=>not equal. */ jcnt = rnnchar[j]; for (k=info[i].numchar; k>=0; k--) { if (jcnt<0) equal = 1; else if (info[i].name[k] != rnnname[j][jcnt]) equal = 1; jcnt--; } if (equal == 0) info[i].regnum = rnnreg[j]; } } printf("Finished finding correct region numbers.\n"); (void)fflush(stdout); /******************************************************************/ /* Check for reciprocity. */ /* Open error file. */ fp2 = fopen(errfile, "wb"); fprintf(fp2, "\nError file for shapefact.\n"); fprintf(fp2, "Shape factor file created: %s\n\n", outfile); fprintf(fp2, "Regions with reciprocity errors greater "); fprintf(fp2, "than 10%%.\n\n"); (void)fflush(fp2); for (i=0; i<numreg; i++) { for (j=0; j<numreg; j++) { rcpi = 0.0; rcpj = 0.0; if ((info[i].lvrays < -ZEROTOL) || (ZEROTOL < info[i].lvrays)) rcpi = info[i].intrays[j] * info[i].engarea /info[i].lvrays; if ((info[j].lvrays < -ZEROTOL) || (ZEROTOL < info[j].lvrays)) rcpj = info[j].intrays[i] * info[j].engarea /info[j].lvrays; rcp_diff = rcpi - rcpj; if (rcp_diff < 0.0) rcp_diff = (-rcp_diff); if ((rcpi < -ZEROTOL) || (ZEROTOL < rcpi)) rcp_pdiff = rcp_diff / rcpi; else rcp_pdiff = 0.0; /* Don't divide by 0. */ /* Print reciprocity errors greater than 10%. */ if (rcp_pdiff > 0.1) { fprintf(fp2, "%d %d %f %f %f %f\n", info[i].regnum, info[j].regnum, rcpi, rcpj, rcp_diff, (rcp_pdiff * 100.0)); (void)fflush(fp2); } } } /* Close error file. */ (void)fclose(fp2); /******************************************************************/ /* Print out shape factor to regular output file. */ if (itype == 0) { fp = fopen(outfile, "wb"); fprintf(fp, "Number of forward rays fired: %llu\n\n", (unsigned long long)loops); (void)fflush(fp); /* Print out structure. */ for (i=0; i<numreg; i++) { /* Print region number, region name, & engine area. */ fprintf(fp, "%d\t%s\t%e\n", info[i].regnum, info[i].name, info[i].engarea); (void)fflush(fp); /* Zero sums for shape factors & rays hit. */ totalsf = 0.0; totalnh = 0.0; for (j=0; j<numreg; j++) { sf = 0.0; if ((info[i].lvrays < -ZEROTOL) || (ZEROTOL < info[i].lvrays)) sf = info[i].intrays[j] / info[i].lvrays; /* Print region number & shape factor. */ fprintf(fp, " %d\t%e\n", info[j].regnum, sf); (void)fflush(fp); /* Add to sum of shape factors & number of hits. */ totalsf += sf; totalnh += info[i].intrays[j]; } /* Print sum of hits & sum of shape factors. */ fprintf(fp, " sum of hits: %f\n", totalnh); fprintf(fp, " sum of shape factors: %f\n\n", totalsf); (void)fflush(fp); } (void)fclose(fp); } /******************************************************************/ /* Create and write to generic shape factor file. */ if (itype == 1) { fp = fopen(outfile, "wb"); for (i=0; i<numreg; i++) { /* Count the number of shape factors. */ icnt = 0; for (j=0; j<numreg; j++) { if (info[i].intrays[j] > ZEROTOL) icnt++; } /* Print the # 5, region number (matches firpass & */ /* secpass), engine area, & number of shape factors. */ fprintf(fp, " 5 %d %e %d\n", info[i].regnum, info[i].engarea, icnt); (void)fflush(fp); for (j=0; j<numreg; j++) { if (info[i].intrays[j] > ZEROTOL) { sf = info[i].intrays[j] / info[i].lvrays; /* Print each region # & shape factor. */ fprintf(fp, " %d %e\n", info[j].regnum, sf); (void)fflush(fp); } } } (void)fclose(fp); } } /* END # 1 */ return 0; }
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); }
/* IEEE patch number of the Bi-Cubic Bezier patch and convert it * to a B-Spline surface (Bezier surfaces are a subset of B-spline surfaces * and output it to a BRL-CAD binary format. */ void dump_patch(int (*patch)[4]) { struct vertex *verts[4]; struct faceuse *fu; struct loopuse *lu; struct edgeuse *eu; int i, j, pt_type; fastf_t *mesh=NULL; fastf_t *ukv=NULL; fastf_t *vkv=NULL; /* U and V parametric Direction Spline parameters * Cubic = order 4, * knot size is Control point + order = 8 * control point size is 4 * point size is 3 */ for ( i=0; i<4; i++ ) verts[i] = (struct vertex *)NULL; fu = nmg_cface( s, verts, 4 ); NMG_CK_FACEUSE( fu ); for ( i=0; i<4; i++ ) { struct vertexuse *vu; vect_t uvw; point_t pnt; int k, j; switch ( i ) { default: case 0: VSET( uvw, 0.0, 0.0, 0.0 ); k = 0; j = 0; break; case 1: VSET( uvw, 1.0, 0.0, 0.0 ); k = 0; j = 3; break; case 2: VSET( uvw, 1.0, 1.0, 0.0 ); k = 3; j = 3; break; case 3: VSET( uvw, 0.0, 1.0, 0.0 ); k = 3; j = 0; break; } VSET( pnt , ducks[patch[k][j]-1].x * 1000 , ducks[patch[k][j]-1].y * 1000 , ducks[patch[k][j]-1].z * 1000 ); nmg_vertex_gv( verts[i], pnt ); for ( BU_LIST_FOR( vu, vertexuse, &verts[i]->vu_hd ) ) nmg_vertexuse_a_cnurb( vu, uvw ); } pt_type = RT_NURB_MAKE_PT_TYPE(3, RT_NURB_PT_XYZ, 0); /* see nurb.h for details */ nmg_face_g_snurb( fu, 4, 4, 8, 8, ukv, vkv, 4, 4, pt_type, mesh ); NMG_CK_FACE( fu->f_p ); NMG_CK_FACE_G_SNURB( fu->f_p->g.snurb_p ); mesh = fu->f_p->g.snurb_p->ctl_points; /* Copy the control points */ for ( i = 0; i< 4; i++) for ( j = 0; j < 4; j++) { *mesh = ducks[patch[i][j]-1].x * 1000; *(mesh+1) = ducks[patch[i][j]-1].y * 1000; *(mesh+2) = ducks[patch[i][j]-1].z * 1000; mesh += 3; } /* Both u and v knot vectors are [ 0 0 0 0 1 1 1 1] */ ukv = fu->f_p->g.snurb_p->u.knots; vkv = fu->f_p->g.snurb_p->v.knots; /* set the knot vectors */ for ( i=0; i<4; i++ ) { *(ukv+i) = 0.0; *(vkv+i) = 0.0; } for ( i=0; i<4; i++ ) { *(ukv+4+i) = 1.0; *(vkv+4+i) = 1.0; } /* set eu geometry */ pt_type = RT_NURB_MAKE_PT_TYPE(2, RT_NURB_PT_UV, 0); /* see nurb.h for details */ lu = BU_LIST_FIRST( loopuse, &fu->lu_hd ); NMG_CK_LOOPUSE( lu ); for ( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) ) { #if 0 nmg_edge_g_cnurb( eu, 2, 0, (fastf_t *)NULL, 2 , pt_type, (fastf_t *)NULL ); #else nmg_edge_g_cnurb_plinear( eu ); #endif } nmg_face_bb( fu->f_p, &tol ); }
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); }
/* * Called from db_walk_tree(). * * This routine must be prepared to run in parallel. */ union tree *do_region_end(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *UNUSED(client_data)) { union tree *ret_tree; struct bu_list vhead; struct nmgregion *r; 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); { char *sofar = db_path_to_string(pathp); bu_log("\ndo_region_end(%d %d%%) %s\n", regions_tried, regions_tried>0 ? (regions_converted * 100) / regions_tried : 0, sofar); bu_free(sofar, "path string"); } if (curtree->tr_op == OP_NOP) return curtree; regions_tried++; if (verbose) bu_log("Attempting to process region %s\n", db_path_to_string(pathp)); ret_tree= process_boolean(curtree, tsp, pathp); if (ret_tree) r = ret_tree->tr_d.td_r; else { if (verbose) bu_log("\tNothing left of this region after Boolean evaluation\n"); regions_written++; /* don't count as a failure */ r = (struct nmgregion *)NULL; } regions_converted++; if (r != (struct nmgregion *)NULL) { struct shell *s; int empty_region=0; int empty_model=0; /* Kill cracks */ s = BU_LIST_FIRST(shell, &r->s_hd); 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; } } s = next_s; } /* kill zero length edgeuses */ if (!empty_region) { empty_model = nmg_kill_zero_length_edgeuses(*tsp->ts_m); } if (!empty_region && !empty_model) { process_triangulation(r, pathp, tsp); regions_written++; } if (!empty_model) nmg_kr(r); } /* * Dispose of original tree, so that all associated dynamic * memory is released now, not at the end of all regions. * A return of TREE_NULL from this routine signals an error, * and there is no point to adding _another_ message to our output, * so we need to cons up an OP_NOP node to return. */ db_free_tree(curtree, &rt_uniresource); /* Does an nmg_kr() */ BU_ALLOC(curtree, union tree); RT_TREE_INIT(curtree); curtree->tr_op = OP_NOP; return curtree; }
/** * 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; }
/** * 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; }
/** * 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 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 ged_bot_fuse(struct ged *gedp, int argc, const char **argv) { struct directory *old_dp, *new_dp; struct rt_db_internal intern, intern2; struct rt_bot_internal *bot; int count=0; static const char *usage = "new_bot old_bot"; struct model *m; struct nmgregion *r; int ret, c, i; struct bn_tol *tol = &gedp->ged_wdbp->wdb_tol; int total = 0; volatile int out_type = 0; /* open edge output type: 0 = none, 1 = show, 2 = plot */ size_t open_cnt; struct bu_vls name_prefix = BU_VLS_INIT_ZERO; /* bu_getopt() options */ static const char *bot_fuse_options = "sp"; static const char *bot_fuse_options_str = "[-s|-p]"; GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR); GED_CHECK_READ_ONLY(gedp, GED_ERROR); GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR); /* initialize result */ bu_vls_trunc(gedp->ged_result_str, 0); /* must be wanting help */ if (argc != 3 && argc != 4) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s %s", argv[0], bot_fuse_options_str, usage); return GED_HELP; } /* Turn off getopt's error messages */ bu_opterr = 0; bu_optind = 1; /* get all the option flags from the command line */ while ((c=bu_getopt(argc, (char **)argv, bot_fuse_options)) != -1) { switch (c) { case 's': { out_type = 1; /* show open edges */ break; } case 'p': { out_type = 2; /* plot open edges */ break; } default : { bu_vls_printf(gedp->ged_result_str, "Unknown option: '%c'", c); return GED_HELP; } } } i = argc - 2; bu_log("%s: start\n", argv[0]); GED_DB_LOOKUP(gedp, old_dp, argv[i+1], LOOKUP_NOISY, GED_ERROR & GED_QUIET); GED_DB_GET_INTERNAL(gedp, &intern, old_dp, bn_mat_identity, &rt_uniresource, GED_ERROR); if (intern.idb_major_type != DB5_MAJORTYPE_BRLCAD || intern.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) { bu_vls_printf(gedp->ged_result_str, "%s: %s is not a BOT solid!\n", argv[0], argv[i+1]); return GED_ERROR; } /* create nmg model structure */ m = nmg_mm(); /* place bot in nmg structure */ bu_log("%s: running rt_bot_tess\n", argv[0]); ret = rt_bot_tess(&r, m, &intern, &gedp->ged_wdbp->wdb_ttol, tol); /* free internal representation of original bot */ rt_db_free_internal(&intern); if (ret != 0) { bu_vls_printf(gedp->ged_result_str, "%s: %s fuse failed (1).\n", argv[0], argv[i+1]); nmg_km(m); return GED_ERROR; } total = 0; /* Step 1 -- the vertices. */ bu_log("%s: running nmg_vertex_fuse\n", argv[0]); count = nmg_vertex_fuse(&m->magic, tol); total += count; bu_log("%s: %s, %d vertex fused\n", argv[0], argv[i+1], count); /* Step 1.5 -- break edges on vertices, before fusing edges */ bu_log("%s: running nmg_break_e_on_v\n", argv[0]); count = nmg_break_e_on_v(&m->magic, tol); total += count; bu_log("%s: %s, %d broke 'e' on 'v'\n", argv[0], argv[i+1], count); if (total) { struct nmgregion *r2; struct shell *s; bu_log("%s: running nmg_make_faces_within_tol\n", argv[0]); /* vertices and/or edges have been moved, * may have created out-of-tolerance faces */ for (BU_LIST_FOR(r2, nmgregion, &m->r_hd)) { for (BU_LIST_FOR(s, shell, &r2->s_hd)) nmg_make_faces_within_tol(s, tol); } } /* Step 2 -- the face geometry */ bu_log("%s: running nmg_model_face_fuse\n", argv[0]); count = nmg_model_face_fuse(m, tol); total += count; bu_log("%s: %s, %d faces fused\n", argv[0], argv[i+1], count); /* Step 3 -- edges */ bu_log("%s: running nmg_edge_fuse\n", argv[0]); count = nmg_edge_fuse(&m->magic, tol); total += count; bu_log("%s: %s, %d edges fused\n", argv[0], argv[i+1], count); bu_log("%s: %s, %d total fused\n", argv[0], argv[i+1], total); if (!BU_SETJUMP) { /* try */ /* convert the nmg model back into a bot */ bot = nmg_bot(BU_LIST_FIRST(shell, &r->s_hd), tol); bu_vls_sprintf(&name_prefix, "open_edges.%s", argv[i]); bu_log("%s: running show_dangling_edges\n", argv[0]); open_cnt = show_dangling_edges(gedp, &m->magic, bu_vls_addr(&name_prefix), out_type); bu_log("%s: WARNING %ld open edges, new BOT may be invalid!!!\n", argv[0], open_cnt); bu_vls_free(&name_prefix); /* free the nmg model structure */ nmg_km(m); } else { /* catch */ BU_UNSETJUMP; bu_vls_printf(gedp->ged_result_str, "%s: %s fuse failed (2).\n", argv[0], argv[i+1]); return GED_ERROR; } BU_UNSETJUMP; RT_DB_INTERNAL_INIT(&intern2); intern2.idb_major_type = DB5_MAJORTYPE_BRLCAD; intern2.idb_type = ID_BOT; intern2.idb_meth = &OBJ[ID_BOT]; intern2.idb_ptr = (void *)bot; GED_DB_DIRADD(gedp, new_dp, argv[i], RT_DIR_PHONY_ADDR, 0, RT_DIR_SOLID, (void *)&intern2.idb_type, GED_ERROR); GED_DB_PUT_INTERNAL(gedp, new_dp, &intern2, &rt_uniresource, GED_ERROR); bu_log("%s: Created new BOT (%s)\n", argv[0], argv[i]); bu_log("%s: Done.\n", argv[0]); return GED_OK; }
int main(int argc, char **argv) { /* START # 99 */ struct application ap; /* Structure passed between functions. */ struct rt_i *rtip; /* Used to build directory. */ int index; /* Index for rt_dirbuild & rt_gettree. */ char idbuf[32]; /* Contains data base info. */ struct region *pr; /* Used in finding region names. */ int numreg; /* Number of regions. */ double centall[3]; /* Center of entire model. */ double minall[3]; /* Minimum of entire model. */ double maxall[3]; /* Maximum of entire model. */ double areaall; /* Surface area of bounding sphere. */ double radall; /* Radius of bounding sphere. */ long seed; /* Seed for random number generator. */ double rayfir; /* Number of rays to be fired. */ double rho, phi, theta;/* Spherical coordinates for starting point. */ double elev, az, rds; /* Elevation, azimuth, & radius for finding vector */ /* in yz-plane. */ double strtpt[3]; /* Starting point. */ double strtdir[3]; /* Starting direction. */ double denom; /* Denominator. */ int ians; /* Answer to question. */ int i, j, k, m; /* Loop counters. */ double r; /* Loop counter. */ double q; /* Temporary variable. */ double s[3], t[3]; /* Temporary variables. */ FILE *fpw; /* Allows a file to be written. */ char outfile[26]; /* Output file name. */ char errfile[26]; /* Error file name. */ FILE *fpw2; /* Allows a file to be written. */ char lwxfile[26]; /* Longwave radiation exchange file for PRISM */ /* (not quite PRISM ready). */ struct bn_unif *msr = NULL; /* Check to see if arguments are implimented correctly. */ if ( (argv[1] == NULL) || (argv[2] == NULL) ) { (void)fprintf(stderr, "\nusage: %s file.g objects\n\n", *argv); } else { /* START # 100 */ /* Find name of output file. */ (void)printf("Enter name of output file (25 char max).\n\t"); (void)fflush(stdout); (void)scanf("%25s", outfile); /* Find name of longwave radiation exchange (lwx) file */ /* for use with PRISM (not quite PRISM ready). */ (void)printf("Enter name of longwave radiation exchange"); (void)printf(" file (25 char max).\n\t"); (void)fflush(stdout); (void)scanf("%25s", lwxfile); /* Find name of error file. */ (void)printf("Enter name of error file (25 char max).\n\t"); (void)fflush(stdout); (void)scanf("%25s", errfile); /* Open files. */ fpw = fopen(outfile, "w"); fpw1 = fopen(errfile, "w"); fpw2 = fopen(lwxfile, "w"); /* Write info to output & error file. */ (void)fprintf(fpw, "\n.g file used: %s\n", argv[1]); (void)fprintf(fpw, "regions used:\n"); (void)fprintf(fpw1, "\n.g file used: %s\n", argv[1]); (void)fprintf(fpw1, "regions used:\n"); i = 2; while (argv[i] != NULL) { (void)fprintf(fpw, "\t%s\n", argv[i]); (void)fprintf(fpw1, "\t%s\n", argv[i]); i++; } (void)fprintf(fpw, "output file created: %s\n", outfile); (void)fprintf(fpw, "error file created: %s\n", errfile); (void)fprintf(fpw, "lwx file created: %s\n", errfile); (void)fflush(fpw); (void)fprintf(fpw1, "output file created: %s\n", outfile); (void)fprintf(fpw1, "error file created: %s\n", errfile); (void)fprintf(fpw1, "lwx file created: %s\n", errfile); (void)fflush(fpw1); /* Build directory. */ index = 1; /* Set index for rt_dirbuild. */ rtip = rt_dirbuild(argv[index], idbuf, sizeof(idbuf)); (void)printf("Database Title: %s\n", idbuf); (void)fflush(stdout); /* Set useair to 0 to show no hits of air. */ rtip->useair = 0; /* Load desired objects. */ index = 2; /* Set index. */ while (argv[index] != NULL) { rt_gettree(rtip, argv[index]); index += 1; } /* Find number of regions. */ numreg = (int)rtip->nregions; (void)fprintf(stderr, "Number of regions: %d\n", numreg); (void)fflush(stderr); /* Malloc everything now that the number of regions is known. */ info = (struct table *)bu_malloc(numreg * sizeof(*info), "info"); for (i=0; i<numreg; i++) { info[i].intrays = (double *)bu_malloc(numreg * sizeof(double), "info[i].intrays"); info[i].sf = (double *)bu_malloc(numreg * sizeof(double), "info[i].sf"); } /* Zero all arrays. */ for (i=0; i<numreg; i++) { /* START # 110 */ info[i].name = "\0"; info[i].lvrays = 0.; for (j=0; j<numreg; j++) { info[i].intrays[j] = 0.; info[i].sf[j] = 0.; } info[i].regarea = 0.; } /* END # 110 */ /* Get database ready by starting prep. */ rt_prep(rtip); /* Find the center of the bounding rpp of entire model. */ centall[X] = rtip->mdl_min[X] + (rtip->mdl_max[X] - rtip->mdl_min[X]) / 2.; centall[Y] = rtip->mdl_min[Y] + (rtip->mdl_max[Y] - rtip->mdl_min[Y]) / 2.; centall[Z] = rtip->mdl_min[Z] + (rtip->mdl_max[Z] - rtip->mdl_min[Z]) / 2.; /* Find minimum and maximum of entire model. */ minall[X] = rtip->mdl_min[X]; minall[Y] = rtip->mdl_min[Y]; minall[Z] = rtip->mdl_min[Z]; maxall[X] = rtip->mdl_max[X]; maxall[Y] = rtip->mdl_max[Y]; maxall[Z] = rtip->mdl_max[Z]; /* Find radius of bounding sphere. */ radall = (maxall[X] - minall[X]) * (maxall[X] - minall[X]) + (maxall[Y] - minall[Y]) * (maxall[Y] - minall[Y]) + (maxall[Z] - minall[Z]) * (maxall[Z] - minall[Z]); /* Add .5 to make sure completely outside the rpp. */ radall = sqrt(radall) / 2. + .5; /* Find surface area of bounding sphere. */ areaall = 4 * M_PI * radall * radall; /* Print info on min, max, center, radius, & surface area */ /* of entire model. */ (void)printf("Min & max for entire model.\n"); (void)printf("\tX: %f - %f\n", minall[X], maxall[X]); (void)printf("\tY: %f - %f\n", minall[Y], maxall[Y]); (void)printf("\tZ: %f - %f\n", minall[Z], maxall[Z]); (void)printf("Center: %f, %f, %f\n\n", centall[X], centall[Y], centall[Z]); (void)printf("Radius: %f\n", radall); (void)printf("Surface Area: %f\n\n", areaall); (void)fflush(stdout); /* Find number of rays to fire. */ (void)printf("Enter the number of rays to be fired.\n\t"); (void)fflush(stdout); (void)scanf("%lf", &rayfir); /* Write info to files. */ (void)fprintf(fpw, "Min & max for entire region:\n"); (void)fprintf(fpw, "\tX: %f - %f\n", minall[X], maxall[X]); (void)fprintf(fpw, "\tY: %f - %f\n", minall[Y], maxall[Y]); (void)fprintf(fpw, "\tZ: %f - %f\n", minall[Z], maxall[Z]); (void)fprintf(fpw, "Center: %f, %f, %f\n", centall[X], centall[Y], centall[Z]); (void)fprintf(fpw, "Radius: %f\n", radall); (void)fprintf(fpw, "Surface area: %f\n", areaall); (void)fprintf(fpw, "Number of rays fired: %f\n\n", rayfir); (void)fflush(fpw); (void)fprintf(fpw1, "Min & max for entire region:\n"); (void)fprintf(fpw1, "\tX: %f - %f\n", minall[X], maxall[X]); (void)fprintf(fpw1, "\tY: %f - %f\n", minall[Y], maxall[Y]); (void)fprintf(fpw1, "\tZ: %f - %f\n", minall[Z], maxall[Z]); (void)fprintf(fpw1, "Center: %f, %f, %f\n", centall[X], centall[Y], centall[Z]); (void)fprintf(fpw1, "Radius: %f\n", radall); (void)fprintf(fpw1, "Surface area: %f\n", areaall); (void)fprintf(fpw1, "Number of rays fired: %f\n\n", rayfir); (void)fflush(fpw1); /* Put region names into structure. */ pr = BU_LIST_FIRST(region, &rtip->HeadRegion); for (i=0; i<numreg; i++) { info[(int)(pr->reg_bit)].name = pr->reg_name; pr = BU_LIST_FORW(region, &(pr->l) ); } (void)printf("Region names in structure.\n"); (void)fflush(stdout); /* Write region names to error file. */ for (i=0; i<numreg; i++) { (void)fprintf(fpw1, "region %d: %s\n", (i + 1), info[i].name); (void)fflush(fpw1); } (void)fprintf(fpw1, "\n"); (void)fflush(fpw1); /* Set seed for random number generator. */ seed = 1; (void)printf("Do you wish to enter your own seed (0) or "); (void)printf("use the default of 1 (1)?\n\t"); (void)fflush(stdout); (void)scanf("%d", &ians); if (ians == 0) { (void)printf("Enter unsigned integer seed.\n\t"); (void)fflush(stdout); (void)scanf("%ld", &seed); } msr = bn_unif_init(seed, 0); (void)printf("Seed initialized\n"); (void)fflush(stdout); /* Set up parameters for rt_shootray. */ RT_APPLICATION_INIT(&ap); ap.a_hit = hit; /* User supplied hit func. */ ap.a_miss = miss; /* User supplied miss func. */ ap.a_overlap = overlap; /* User supplied overlap func. */ ap.a_rt_i = rtip; /* Pointer from rt_dirbuild. */ ap.a_onehit = 0; /* Look at all hits. */ ap.a_level = 0; /* Recursion level for diagnostics. */ ap.a_resource = 0; /* Address for resource struct. */ /* * (void)printf("Parameters for rt_shootray set.\n"); * (void)fflush(stdout); */ /* Loop through for each ray fired. */ for (r=0; r<rayfir; r++) { /* START # 150 */ /* * (void)printf("In loop - %f\n", r); * (void)fflush(stdout); */ /* Find point on the bounding sphere. The negative */ /* of the unit vector of this point will be the */ /* firing direction. */ q = BN_UNIF_DOUBLE(msr) + 0.5; theta = q * 2. * M_PI; q = BN_UNIF_DOUBLE(msr) + 0.5; phi = (q * 2.) - 1.; phi = acos(phi); rho = radall; strtdir[X] = rho * sin(phi) * cos(theta); strtdir[Y] = rho * sin(phi) * sin(theta); strtdir[Z] = rho * cos(phi); /* Elevation & azimuth for finding a vector in a plane. */ elev = M_PI / 2. - phi; az = theta; /* Find vector in yz-plane. */ q = BN_UNIF_DOUBLE(msr) + 0.5; theta = q * 2. * M_PI; q = BN_UNIF_DOUBLE(msr) + 0.5; rds = rho * sqrt(q); s[X] = 0.; s[Y] = rds * cos(theta); s[Z] = rds * sin(theta); /* Rotate vector. */ t[X] = s[X] * cos(elev) * cos(az) - s[Z] * sin(elev) * cos(az) - s[Y] * sin(az); t[Y] = s[X] * cos(elev) * sin(az) - s[Z] * sin(elev) * sin(az) + s[Y] * cos(az); t[Z] = s[X] * sin(elev) + s[Z] * cos(elev); /* Translate the point. This is the starting point. */ strtpt[X] = t[X] + strtdir[X]; strtpt[Y] = t[Y] + strtdir[Y]; strtpt[Z] = t[Z] + strtdir[Z]; /* Now transfer the starting point so that it is in the */ /* absolute coordinates not the origin's. */ strtpt[X] += centall[X]; strtpt[Y] += centall[Y]; strtpt[Z] += centall[Z]; /* Normalize starting direction & make negative. */ denom = strtdir[X] *strtdir[X] + strtdir[Y] *strtdir[Y] + strtdir[Z] *strtdir[Z]; denom = sqrt(denom); strtdir[X] /= (-denom); strtdir[Y] /= (-denom); strtdir[Z] /= (-denom); /* Set up firing point & direction. */ ap.a_ray.r_pt[X] = strtpt[X]; ap.a_ray.r_pt[Y] = strtpt[Y]; ap.a_ray.r_pt[Z] = strtpt[Z]; ap.a_ray.r_dir[X] = strtdir[X]; ap.a_ray.r_dir[Y] = strtdir[Y]; ap.a_ray.r_dir[Z] = strtdir[Z]; /* * (void)printf("Calling rt_shootray.\n"); * (void)fflush(stdout); */ /* Call rt_shootray. */ (void)rt_shootray(&ap); /* * (void)printf("Rt_shootray finished.\n"); * (void)fflush(stdout); */ } /* END # 150 */ /* * (void)printf("Finished loop.\n"); * (void)fflush(stdout); */ for (i=0; i<numreg; i++) { /* START # 160 */ /* Write region names to output file. */ (void)fprintf(fpw, "Region %d: %s\n", (i+1), info[i].name); (void)fflush(fpw); /* Find shape factors & print. */ if (info[i].lvrays == 0) { /* START # 1060 */ (void)fprintf(fpw1, "** ERROR - # or rays hitting region "); (void)fprintf(fpw1, "%d is 0. **\n", i); (void)fflush(fpw1); } /* END # 1060 */ else { /* START # 1070 */ /* Must divide by 2. since looking forwards & backwards. */ info[i].regarea = info[i].lvrays / rayfir * areaall / 2.; for (j=0; j<numreg; j++) { /* START # 1080 */ info[i].sf[j] = info[i].intrays[j] / info[i].lvrays; (void)fprintf(fpw, "\t%d %d %f\n", (i + 1), (j + 1), info[i].sf[j]); (void)fflush(fpw); (void)fprintf(fpw1, "reg %d - reg %d - rays leave ", (i + 1), (j + 1)); (void)fprintf(fpw1, "& int %f - rays leave %f ", info[i].intrays[j], info[i].lvrays); (void)fprintf(fpw1, "- sf %f - area %f\n", info[i].sf[j], info[i].regarea); (void)fflush(fpw1); } /* END # 1080 */ } /* END # 1070 */ } /* END # 160 */ /* Write lwx file. */ (void)fprintf(fpw2, "Longwave Radiation Exchange Factors "); (void)fprintf(fpw2, "for %s\n", argv[1]); (void)fprintf(fpw2, "Number of Regions = %4d\n", numreg); (void)fprintf(fpw2, "TEMIS\n\n"); for (i=0; i<numreg; i++) { /* START # 1090 */ (void)fprintf(fpw2, "Region\tArea\tEmissivity\n"); /* Area is put into square meters. */ (void)fprintf(fpw2, "%d\t%f\n", (i + 1), (info[i].regarea / 1000. / 1000.)); /* Count the number of shape factors. */ k = 0; for (j=0; j<numreg; j++) { if (info[i].sf[j] != 0.) k++; } (void)fprintf(fpw2, "Bij\t%d\n", k); /* Print shape factors. */ m = 0; for (j=0; j<numreg; j++) { /* START # 1100 */ if (info[i].sf[j] != 0.) { /* START # 1110 */ (void)fprintf(fpw2, "%4d %.4f ", (j + 1), info[i].sf[j]); m++; if (m == 5) { /* START # 1120 */ m = 0; (void)fprintf(fpw2, "\n"); } /* END # 1120 */ } /* END # 1110 */ } /* END # 1100 */ if (m != 0) (void)fprintf(fpw2, "\n"); (void)fprintf(fpw2, " Gnd Sky\n\n"); (void)fflush(fpw2); } /* END # 1090 */ /* free memory */ for (i=0; i<numreg; i++) { bu_free(info[i].intrays, "info[i].intrays"); bu_free(info[i].sf, "info[i].sf"); } bu_free(info, "info"); /* Close files. */ (void)fclose(fpw); (void)fclose(fpw1); (void)fclose(fpw2); } /* END # 100 */ return 0; } /* END # 99 */
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; }
static struct loopuse * nmg_construct_loopuse(void *parent, const struct loopuse *original, void **structArray) { struct loopuse *ret; NMG_GETSTRUCT(ret, loopuse); ret->l.magic = NMG_LOOPUSE_MAGIC; ret->up.magic_p = (uint32_t *)parent; ret->lumate_p = (struct loopuse *)NULL; ret->orientation = original->orientation; ret->l_p = (struct loop *)NULL; BU_LIST_INIT(&ret->down_hd); ret->index = original->index; structArray[ret->index] = ret; if (original->lumate_p != NULL) { ret->lumate_p = (struct loopuse *)structArray[original->lumate_p->index]; /* because it's tricky to choose the right parent for the mate * wait until it's created and set eumate_p afterwards */ if (ret->lumate_p != NULL) ret->lumate_p->lumate_p = ret; } if (original->l_p != NULL) { ret->l_p = (struct loop *)structArray[original->l_p->index]; if (ret->l_p == 0) ret->l_p = nmg_construct_loop(ret, original->l_p, structArray); } switch (BU_LIST_FIRST_MAGIC(&original->down_hd)) { case NMG_VERTEXUSE_MAGIC: { const struct vertexuse *originalVertexUse = BU_LIST_FIRST(vertexuse, &original->down_hd); struct vertexuse *newVertexUse = (struct vertexuse *)structArray[originalVertexUse->index]; if (newVertexUse == NULL) newVertexUse = nmg_construct_vertexuse(ret, originalVertexUse, structArray); BU_LIST_INSERT(&ret->down_hd, &newVertexUse->l); } break; case NMG_EDGEUSE_MAGIC: { const struct edgeuse *originalEdgeUse; for (BU_LIST_FOR(originalEdgeUse, edgeuse, &original->down_hd)) { struct edgeuse *newEdgeUse = (struct edgeuse *)structArray[originalEdgeUse->index]; if (newEdgeUse == NULL) newEdgeUse = nmg_construct_edgeuse(ret, originalEdgeUse, structArray); BU_LIST_INSERT(&ret->down_hd, &newEdgeUse->l); } } break; default: /* FIXME: any more cases? any action to take? */ break; } return ret; }
/** * 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 */ }
/* * Called from db_walk_tree(). * * This routine must be prepared to run in parallel. */ union tree * do_region_end(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *UNUSED(client_data)) { struct nmgregion *r; struct bu_list vhead; union tree *ret_tree; if (verbose) bu_log("do_region_end: regionid = %d\n", tsp->ts_regionid); RT_CK_TESS_TOL(tsp->ts_ttol); BN_CK_TOL(tsp->ts_tol); NMG_CK_MODEL(*tsp->ts_m); BU_LIST_INIT(&vhead); if (RT_G_DEBUG&DEBUG_TREEWALK || verbose) { char *sofar = db_path_to_string(pathp); bu_log("\ndo_region_end(%d %d%%) %s\n", regions_tried, regions_tried>0 ? (regions_converted * 100) / regions_tried : 0, sofar); bu_free(sofar, "path string"); } if (curtree->tr_op == OP_NOP) return curtree; regions_tried++; if (verbose) bu_log("\tEvaluating region\n"); ret_tree = process_boolean(curtree, tsp, pathp); if (ret_tree) r = ret_tree->tr_d.td_r; else r = (struct nmgregion *)NULL; regions_converted++; if (r != (struct nmgregion *)NULL) { struct shell *s; int empty_region = 0; int empty_model = 0; /* Kill cracks */ s = BU_LIST_FIRST(shell, &r->s_hd); 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; } } s = next_s; } /* kill zero length edgeuses */ if (!empty_region) { empty_model = nmg_kill_zero_length_edgeuses(*tsp->ts_m); } if (!empty_region && !empty_model) { /* Write the region to the EUCLID file */ Write_euclid_region(r, tsp); } if (!empty_model) nmg_kr(r); } /* * Dispose of original tree, so that all associated dynamic * memory is released now, not at the end of all regions. * A return of TREE_NULL from this routine signals an error, * so we need to cons up an OP_NOP node to return. */ db_free_tree(curtree, &rt_uniresource); /* Does an nmg_kr() */ BU_ALLOC(curtree, union tree); RT_TREE_INIT(curtree); curtree->tr_op = OP_NOP; return curtree; }
int main(int argc, char **argv) { int n; if (argc < 2) { fprintf(stderr, "%s", srv_usage); return 1; } while (argv[1][0] == '-') { if (BU_STR_EQUAL(argv[1], "-d")) { debug++; } else if (BU_STR_EQUAL(argv[1], "-x")) { sscanf(argv[2], "%x", (unsigned int *)&RTG.debug); argc--; argv++; } else if (BU_STR_EQUAL(argv[1], "-X")) { sscanf(argv[2], "%x", (unsigned int *)&rdebug); argc--; argv++; } else { fprintf(stderr, "%s", srv_usage); return 3; } argc--; argv++; } if (argc != 3 && argc != 4) { fprintf(stderr, "%s", srv_usage); return 2; } control_host = argv[1]; tcp_port = argv[2]; /* Note that the LIBPKG error logger can not be * "bu_log", as that can cause bu_log to be entered recursively. * Given the special version of bu_log in use here, * that will result in a deadlock in bu_semaphore_acquire(res_syscall)! * libpkg will default to stderr via pkg_errlog(), which is fine. */ pcsrv = pkg_open(control_host, tcp_port, "tcp", "", "", pkgswitch, NULL); if (pcsrv == PKC_ERROR) { fprintf(stderr, "rtsrv: unable to contact %s, port %s\n", control_host, tcp_port); return 1; } if (argc == 4) { /* Slip one command to dispatcher */ (void)pkg_send(MSG_CMD, argv[3], strlen(argv[3])+1, pcsrv); /* Prevent chasing the package with an immediate TCP close */ sleep(1); pkg_close(pcsrv); return 0; } #ifdef SO_SNDBUF /* increase the default send buffer size to 32k since we're * sending pixels more than likely. */ { int val = 32767; n = setsockopt(pcsrv->pkc_fd, SOL_SOCKET, SO_SNDBUF, (const void *)&val, sizeof(val)); if (n < 0) perror("setsockopt: SO_SNDBUF"); } #endif if (!debug) { /* A fresh process */ if (fork()) return 0; /* Go into our own process group */ n = bu_process_id(); #ifdef HAVE_SETPGID if (setpgid(n, n) < 0) perror("setpgid"); #else /* SysV uses setpgrp with no args and it can't fail, * obsoleted by setpgid. */ setpgrp(); #endif /* * Unless controller process has specifically said * that this is an interactive session, e.g., for a demo, * drop to the lowest sensible priority. */ if (!interactive) { bu_nice_set(19); /* lowest priority */ } /* Close off the world */ fclose(stdin); fclose(stdout); fclose(stderr); (void)close(0); (void)close(1); (void)close(2); /* For stdio & perror safety, reopen 0, 1, 2 */ (void)open("/dev/null", 0); /* to fd 0 */ n = dup(0); /* to fd 1 */ if (n == -1) perror("dup"); n = dup(0); /* to fd 2 */ if (n == -1) perror("dup"); #if defined(HAVE_SYS_IOCTL_H) && defined(TIOCNOTTY) n = open("/dev/tty", 2); if (n >= 0) { (void)ioctl(n, TIOCNOTTY, 0); (void)close(n); } #endif } /* Send our version string */ if (pkg_send(MSG_VERSION, PROTOCOL_VERSION, strlen(PROTOCOL_VERSION)+1, pcsrv) < 0) { fprintf(stderr, "pkg_send MSG_VERSION error\n"); return 1; } if (debug) fprintf(stderr, "PROTOCOL_VERSION='%s'\n", PROTOCOL_VERSION); /* * Now that the fork() has been done, it is safe to initialize * the parallel processing support. */ avail_cpus = bu_avail_cpus(); /* Need to set rtg_parallel non_zero here for RES_INIT to work */ npsw = avail_cpus; if (npsw > 1) { RTG.rtg_parallel = 1; } else RTG.rtg_parallel = 0; bu_semaphore_init(RT_SEM_LAST); bu_log("using %d of %d cpus\n", npsw, avail_cpus); /* * Initialize the non-parallel memory resource. * The parallel guys are initialized after the rt_dirbuild(). */ rt_init_resource(&rt_uniresource, MAX_PSW, NULL); bn_rand_init(rt_uniresource.re_randptr, MAX_PSW); BU_LIST_INIT(&WorkHead); for (;;) { struct pkg_queue *lp; fd_set ifds; struct timeval tv; /* First, process any packages in library buffers */ if (pkg_process(pcsrv) < 0) { bu_log("pkg_get error\n"); break; } /* Second, see if any input to read */ FD_ZERO(&ifds); FD_SET(pcsrv->pkc_fd, &ifds); tv.tv_sec = BU_LIST_NON_EMPTY(&WorkHead) ? 0L : 9999L; tv.tv_usec = 0L; if (select(pcsrv->pkc_fd+1, &ifds, (fd_set *)0, (fd_set *)0, &tv) != 0) { n = pkg_suckin(pcsrv); if (n < 0) { bu_log("pkg_suckin error\n"); break; } else if (n == 0) { /* EOF detected */ break; } else { /* All is well */ } } /* Third, process any new packages in library buffers */ if (pkg_process(pcsrv) < 0) { bu_log("pkg_get error\n"); break; } /* Finally, more work may have just arrived, check our list */ if (BU_LIST_NON_EMPTY(&WorkHead)) { lp = BU_LIST_FIRST(pkg_queue, &WorkHead); BU_LIST_DEQUEUE(&lp->l); switch (lp->type) { case MSG_MATRIX: ph_matrix((struct pkg_conn *)0, lp->buf); break; case MSG_LINES: ph_lines((struct pkg_conn *)0, lp->buf); break; case MSG_OPTIONS: ph_options((struct pkg_conn *)0, lp->buf); break; case MSG_GETTREES: ph_gettrees((struct pkg_conn *)0, lp->buf); break; default: bu_log("bad list element, type=%d\n", lp->type); return 33; } BU_PUT(lp, struct pkg_queue); } } return 0; /* bu_exit(0, NULL) */ }
union tree * nmg_region_end(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *UNUSED(client_data)) { struct nmgregion *r; struct bu_list vhead; union tree *ret_tree; char *name; RT_CK_TESS_TOL(tsp->ts_ttol); BN_CK_TOL(tsp->ts_tol); NMG_CK_MODEL(*tsp->ts_m); BARRIER_CHECK; BU_LIST_INIT(&vhead); if (RT_G_DEBUG&DEBUG_TREEWALK || verbose) { bu_log("\nConverted %d%% so far (%d of %d)\n", regions_tried>0 ? (regions_converted * 100) / regions_tried : 0, regions_converted, regions_tried ); } if (curtree->tr_op == OP_NOP) return curtree; name = db_path_to_string( pathp ); bu_log( "Attempting %s\n", name ); regions_tried++; ret_tree = process_boolean(curtree, tsp, pathp); if ( ret_tree ) r = ret_tree->tr_d.td_r; else r = (struct nmgregion *)NULL; bu_free( name, "db_path_to_string" ); regions_converted++; if (r != (struct nmgregion *)NULL) { struct shell *s; int empty_region=0; int empty_model=0; /* Kill cracks */ s = BU_LIST_FIRST( shell, &r->s_hd ); 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; } } s = next_s; } /* kill zero length edgeuses */ if ( !empty_region ) { empty_model = nmg_kill_zero_length_edgeuses( *tsp->ts_m ); } if ( !empty_region && !empty_model ) { /* Write the nmgregion to the output file */ nmg_2_vrml( outfp, pathp, r->m_p, &tsp->ts_mater ); } /* NMG region is no longer necessary */ if ( !empty_model ) nmg_kr(r); } else bu_log( "WARNING: Nothing left after Boolean evaluation of %s\n", db_path_to_string( pathp ) ); /* * Dispose of original tree, so that all associated dynamic * memory is released now, not at the end of all regions. * A return of TREE_NULL from this routine signals an error, * so we need to cons up an OP_NOP node to return. */ db_free_tree(curtree, &rt_uniresource); /* Does an nmg_kr() */ BU_ALLOC(curtree, union tree); RT_TREE_INIT(curtree); curtree->tr_op = OP_NOP; BARRIER_CHECK; return curtree; }
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); }
void process_non_light(struct model *m) { /* static due to bu exception handling */ static struct shell *s; static struct shell *next_s; static struct faceuse *fu; static struct faceuse *next_fu; static struct loopuse *lu; static struct nmgregion *reg; /* triangulate any faceuses with holes */ for ( BU_LIST_FOR( reg, nmgregion, &m->r_hd ) ) { NMG_CK_REGION( reg ); s = BU_LIST_FIRST( shell, ®->s_hd ); while ( BU_LIST_NOT_HEAD( s, ®->s_hd ) ) { NMG_CK_SHELL( s ); next_s = BU_LIST_PNEXT( shell, &s->l ); fu = BU_LIST_FIRST( faceuse, &s->fu_hd ); while ( BU_LIST_NOT_HEAD( &fu->l, &s->fu_hd ) ) { int shell_is_dead=0; NMG_CK_FACEUSE( fu ); next_fu = BU_LIST_PNEXT( faceuse, &fu->l ); if ( fu->orientation != OT_SAME ) { fu = next_fu; continue; } if ( fu->fumate_p == next_fu ) { /* make sure next_fu is not the mate of fu */ next_fu = BU_LIST_PNEXT( faceuse, &next_fu->l ); } /* check if this faceuse has any holes */ for ( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) ) { NMG_CK_LOOPUSE( lu ); if ( lu->orientation == OT_OPPOSITE ) { /* this is a hole, so * triangulate the faceuse */ if ( !BU_SETJUMP ) { /* try */ if ( nmg_triangulate_fu( fu, &tol ) ) { if ( nmg_kfu( fu ) ) { (void) nmg_ks( s ); shell_is_dead = 1; } } } else { /* catch */ bu_log( "A face has failed triangulation!\n" ); if ( next_fu == fu->fumate_p ) next_fu = BU_LIST_PNEXT( faceuse, &next_fu->l ); if ( nmg_kfu( fu ) ) { (void) nmg_ks( s ); shell_is_dead = 1; } } BU_UNSETJUMP; break; } } if ( shell_is_dead ) break; fu = next_fu; } s = next_s; } } }
/* * 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; }
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; }