/** * master hook function for the 'tracker' command used to create * copies of objects along a spline path. */ int f_tracker(ClientData UNUSED(clientData), Tcl_Interp *interp, int argc, const char *argv[]) { size_t ret; struct spline s; vect_t *verts = (vect_t *)NULL; struct link *links = (struct link *)NULL; int opt; size_t i, j, k, inc; size_t n_verts, n_links; int arg = 1; FILE *points = (FILE *)NULL; char tok[81] = {0}, line[81] = {0}; char ch; fastf_t totlen = 0.0; fastf_t len, olen; fastf_t dist_to_next; fastf_t min, max, mid; fastf_t pt[3] = {0}; int no_draw = 0; /* allow interrupts */ if (setjmp(jmp_env) == 0) (void)signal(SIGINT, sig3); else return TCL_OK; bu_optind = 1; while ((opt = bu_getopt(argc, (char * const *)argv, "fh")) != EOF) { switch (opt) { case 'f': no_draw = 1; arg++; break; case 'h': Tcl_AppendResult(interp, "tracker [-fh] [# links] [increment] [spline.iges] [link...]\n\n", (char *)NULL); Tcl_AppendResult(interp, "-f:\tDo not draw the links as they are made.\n", (char *)NULL); Tcl_AppendResult(interp, "-h:\tPrint this message.\n\n", (char *)NULL); Tcl_AppendResult(interp, "\tThe prototype link(s) should be placed so that one\n", (char *)NULL); Tcl_AppendResult(interp, "\tpin's vertex lies on the origin and points along the\n", (char *)NULL); Tcl_AppendResult(interp, "\ty-axis, and the link should lie along the positive x-axis.\n\n", (char *)NULL); Tcl_AppendResult(interp, "\tIf two or more sublinks comprise the link, they are specified in this manner:\n", (char *)NULL); Tcl_AppendResult(interp, "\t<link1> <%% of total link> <link2> <%% of total link> ....\n", (char *)NULL); return TCL_OK; } } if (argc < arg+1) { Tcl_AppendResult(interp, MORE_ARGS_STR, "Enter number of links: ", (char *)NULL); return TCL_ERROR; } n_verts = atoi(argv[arg++])+1; if (argc < arg+1) { Tcl_AppendResult(interp, MORE_ARGS_STR, "Enter amount to increment parts by: ", (char *)NULL); return TCL_ERROR; } inc = atoi(argv[arg++]); if (argc < arg+1) { Tcl_AppendResult(interp, MORE_ARGS_STR, "Enter spline file name: ", (char *)NULL); return TCL_ERROR; } if ((points = fopen(argv[arg++], "r")) == NULL) { fprintf(stdout, "tracker: couldn't open points file %s.\n", argv[arg-1]); return TCL_ERROR; } if (argc < arg+1) { Tcl_AppendResult(interp, MORE_ARGS_STR, "Enter prototype link name: ", (char *)NULL); fclose(points); return TCL_ERROR; } /* Prepare vert list *****************************/ n_links = ((argc-3)/2)>1?((argc-3)/2):1; verts = (vect_t *)malloc(sizeof(vect_t) * n_verts * (n_links+2)); /* Read in links names and link lengths **********/ links = (struct link *)malloc(sizeof(struct link)*n_links); for (i = arg; i < (size_t)argc; i+=2) { double scan; bu_vls_strcpy(&links[(i-arg)/2].name, argv[i]); if (argc > arg+1) { sscanf(argv[i+1], "%lf", &scan); /* double to fastf_t */ links[(i-arg)/2].pct = scan; } else { links[(i-arg)/2].pct = 1.0; } totlen += links[(i-arg)/2].pct; } if (!ZERO(totlen - 1.0)) fprintf(stdout, "ERROR\n"); /* Read in knots from specified file *************/ do bu_fgets(line, 81, points); while (!BU_STR_EQUAL(strtok(line, ","), "112")); bu_strlcpy(tok, strtok(NULL, ","), sizeof(tok)); bu_strlcpy(tok, strtok(NULL, ","), sizeof(tok)); bu_strlcpy(tok, strtok(NULL, ","), sizeof(tok)); bu_strlcpy(tok, strtok(NULL, ","), sizeof(tok)); s.n_segs = atoi(tok); s.t = (fastf_t *)bu_malloc(sizeof(fastf_t) * (s.n_segs+1), "t"); s.k = (struct knot *)bu_malloc(sizeof(struct knot) * (s.n_segs+1), "k"); for (i = 0; i <= s.n_segs; i++) { bu_strlcpy(tok, strtok(NULL, ","), sizeof(tok)); if (strstr(tok, "P") != NULL) { bu_fgets(line, 81, points); bu_fgets(line, 81, points); bu_strlcpy(tok, strtok(line, ","), sizeof(tok)); } s.t[i] = atof(tok); } for (i = 0; i <= s.n_segs; i++) for (j = 0; j < 3; j++) { for (k = 0; k < 4; k++) { bu_strlcpy(tok, strtok(NULL, ","), sizeof(tok)); if (strstr(tok, "P") != NULL) { bu_fgets(line, 81, points); bu_fgets(line, 81, points); bu_strlcpy(tok, strtok(line, ","), sizeof(tok)); } s.k[i].c[j][k] = atof(tok); } s.k[i].pt[j] = s.k[i].c[j][0]; } fclose(points); /* Interpolate link vertices *********************/ for (i = 0; i < s.n_segs; i++) /* determine initial track length */ totlen += DIST_PT_PT(s.k[i].pt, s.k[i+1].pt); len = totlen/(n_verts-1); VMOVE(verts[0], s.k[0].pt); olen = 2*len; for (i = 0; (fabs(olen-len) >= VUNITIZE_TOL) && (i < 250); i++) { /* number of track iterations */ fprintf(stdout, "."); fflush(stdout); for (j = 0; j < n_links; j++) /* set length of each link based on current track length */ links[j].len = len * links[j].pct; min = 0; max = s.t[s.n_segs]; mid = 0; for (j = 0; j < n_verts+1; j++) /* around the track once */ for (k = 0; k < n_links; k++) { /* for each sub-link */ if ((k == 0) && (j == 0)) {continue;} /* the first sub-link of the first link is already in position */ min = mid; max = s.t[s.n_segs]; mid = (min+max)/2; interp_spl(mid, s, pt); dist_to_next = (k > 0) ? links[k-1].len : links[n_links-1].len; /* links[k].len;*/ while (fabs(DIST_PT_PT(verts[n_links*j+k-1], pt) - dist_to_next) >= VUNITIZE_TOL) { if (DIST_PT_PT(verts[n_links*j+k-1], pt) > dist_to_next) { max = mid; mid = (min+max)/2; } else { min = mid; mid = (min+max)/2; } interp_spl(mid, s, pt); if (fabs(min-max) <= VUNITIZE_TOL) {break;} } interp_spl(mid, s, verts[n_links*j+k]); } interp_spl(s.t[s.n_segs], s, verts[n_verts*n_links-1]); totlen = 0.0; for (j = 0; j < n_verts*n_links-1; j++) totlen += DIST_PT_PT(verts[j], verts[j+1]); olen = len; len = totlen/(n_verts-1); } fprintf(stdout, "\n"); /* Write out interpolation info ******************/ fprintf(stdout, "%ld Iterations; Final link lengths:\n", (unsigned long)i); for (i = 0; i < n_links; i++) fprintf(stdout, " %s\t%.15f\n", bu_vls_addr(&links[i].name), links[i].len); fflush(stdin); /* Place links on vertices ***********************/ fprintf(stdout, "Continue? [y/n] "); ret = fscanf(stdin, "%c", &ch); if (ret != 1) perror("fscanf"); if (ch == 'y') { struct clone_state state; struct directory **dps = (struct directory **)NULL; char *vargs[3]; for (i = 0; i < 2; i++) vargs[i] = (char *)bu_calloc(CLONE_BUFSIZE, sizeof(char), "alloc vargs[i]"); vargs[0][0] = 'e'; state.interp = interp; state.incr = inc; state.n_copies = 1; state.draw_obj = 0; state.miraxis = W; dps = (struct directory **)bu_calloc(n_links, sizeof(struct directory *), "alloc dps array"); /* rots = (vect_t *)bu_malloc(sizeof(vect_t)*n_links, "alloc rots");*/ for (i = 0; i < n_links; i++) { /* global dbip */ dps[i] = db_lookup(dbip, bu_vls_addr(&links[i].name), LOOKUP_QUIET); /* VSET(rots[i], 0, 0, 0);*/ } for (i = 0; i < n_verts-1; i++) { for (j = 0; j < n_links; j++) { if (i == 0) { VSCALE(state.trans, verts[n_links*i+j], local2base); } else VSUB2SCALE(state.trans, verts[n_links*(i-1)+j], verts[n_links*i+j], local2base); VSCALE(state.rpnt, verts[n_links*i+j], local2base); VSUB2(pt, verts[n_links*i+j], verts[n_links*i+j+1]); VSET(state.rot, 0, (M_PI - atan2(pt[Z], pt[X])), -atan2(pt[Y], sqrt(pt[X]*pt[X]+pt[Z]*pt[Z]))); VSCALE(state.rot, state.rot, RAD2DEG); /* VSUB2(state.rot, state.rot, rots[j]); VADD2(rots[j], state.rot, rots[j]); */ state.src = dps[j]; /* global dbip */ dps[j] = copy_object(dbip, &rt_uniresource, &state); bu_strlcpy(vargs[1], dps[j]->d_namep, CLONE_BUFSIZE); if (!no_draw || !is_dm_null()) { drawtrees(2, (const char **)vargs, 1); size_reset(); new_mats(); color_soltab(); refresh(); } fprintf(stdout, "."); fflush(stdout); } } fprintf(stdout, "\n"); bu_free(dps, "free dps array"); for (i = 0; i < 2; i++) bu_free(vargs[i], "free vargs[i]"); } free(s.t); free(s.k); free(links); free(verts); (void)signal(SIGINT, SIG_IGN); return TCL_OK; }
/** * Returns - * 0 OK * !0 failure */ int rt_arbn_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip) { struct rt_arbn_internal *aip; vect_t work; fastf_t f; size_t i; size_t j; size_t k; int *used = (int *)0; /* plane eqn use count */ const struct bn_tol *tol = &rtip->rti_tol; RT_CK_DB_INTERNAL(ip); aip = (struct rt_arbn_internal *)ip->idb_ptr; RT_ARBN_CK_MAGIC(aip); used = (int *)bu_malloc(aip->neqn*sizeof(int), "arbn used[]"); /* * ARBN must be convex. Test for concavity. * Byproduct is an enumeration of all the vertices, * which are used to make the bounding RPP. No need * to call the bbox routine, as the work must be duplicated * here to count faces. */ /* Zero face use counts * and make sure normal vectors are unit vectors */ for (i = 0; i < aip->neqn; i++) { double normalLen = MAGNITUDE(aip->eqn[i]); double scale; if (ZERO(normalLen)) { bu_log("arbn has zero length normal vector\n"); return 1; } scale = 1.0 / normalLen; HSCALE(aip->eqn[i], aip->eqn[i], scale); used[i] = 0; } for (i = 0; i < aip->neqn-2; i++) { for (j=i+1; j<aip->neqn-1; j++) { double dot; /* If normals are parallel, no intersection */ dot = VDOT(aip->eqn[i], aip->eqn[j]); if (BN_VECT_ARE_PARALLEL(dot, tol)) continue; /* Have an edge line, isect with higher numbered planes */ for (k=j+1; k<aip->neqn; k++) { size_t m; size_t next_k; point_t pt; next_k = 0; if (bn_mkpoint_3planes(pt, aip->eqn[i], aip->eqn[j], aip->eqn[k]) < 0) continue; /* See if point is outside arb */ for (m = 0; m < aip->neqn; m++) { if (i == m || j == m || k == m) continue; if (VDOT(pt, aip->eqn[m])-aip->eqn[m][3] > tol->dist) { next_k = 1; break; } } if (next_k != 0) continue; VMINMAX(stp->st_min, stp->st_max, pt); /* Increment "face used" counts */ used[i]++; used[j]++; used[k]++; } } } /* If any planes were not used, then arbn is not convex */ for (i = 0; i < aip->neqn; i++) { if (used[i] != 0) continue; /* face was used */ bu_log("arbn(%s) face %zu unused, solid is not convex\n", stp->st_name, i); bu_free((char *)used, "arbn used[]"); return -1; /* BAD */ } bu_free((char *)used, "arbn used[]"); stp->st_specific = (void *)aip; ip->idb_ptr = ((void *)0); /* indicate we stole it */ VADD2SCALE(stp->st_center, stp->st_min, stp->st_max, 0.5); VSUB2SCALE(work, stp->st_max, stp->st_min, 0.5); f = work[X]; if (work[Y] > f) f = work[Y]; if (work[Z] > f) f = work[Z]; stp->st_aradius = f; stp->st_bradius = MAGNITUDE(work); return 0; /* OK */ }