int
main(int argc, char **argv)
{
    int c;
    double percent;
    int i;

    bu_setprogname(argv[0]);
    bu_setlinebuf(stderr);

    RTG.debug = 0;

    tree_state = rt_initial_tree_state;	/* struct copy */
    tree_state.ts_tol = &tol;
    tree_state.ts_ttol = &ttol;
    tree_state.ts_m = &the_model;

    ttol.magic = RT_TESS_TOL_MAGIC;
    /* Defaults, updated by command line options. */
    ttol.abs = 0.0;
    ttol.rel = 0.01;
    ttol.norm = 0.0;

    /* FIXME: These need to be improved */
    tol.magic = BN_TOL_MAGIC;
    tol.dist = BN_TOL_DIST;
    tol.dist_sq = tol.dist * tol.dist;
    tol.perp = 1e-6;
    tol.para = 1 - tol.perp;

    the_model = nmg_mm();
    BU_LIST_INIT(&RTG.rtg_vlfree);	/* for vlist macros */

    /* Get command line arguments. */
    while ((c = bu_getopt(argc, argv, "a:n:o:r:vx:D:P:X:e:ih?")) != -1) {
	switch (c) {
	    case 'a':		/* Absolute tolerance. */
		ttol.abs = atof(bu_optarg);
		ttol.rel = 0.0;
		break;
	    case 'n':		/* Surface normal tolerance. */
		ttol.norm = atof(bu_optarg);
		ttol.rel = 0.0;
		break;
	    case 'o':		/* Output file name. */
		output_file = bu_optarg;
		break;
	    case 'r':		/* Relative tolerance. */
		ttol.rel = atof(bu_optarg);
		break;
	    case 'v':
		verbose++;
		break;
	    case 'P':
		ncpu = atoi(bu_optarg);
		break;
	    case 'x':
		sscanf(bu_optarg, "%x", (unsigned int *)&RTG.debug);
		break;
	    case 'D':
		tol.dist = atof(bu_optarg);
		tol.dist_sq = tol.dist * tol.dist;
		rt_pr_tol(&tol);
		break;
	    case 'X':
		sscanf(bu_optarg, "%x", (unsigned int *)&RTG.NMG_debug);
		NMG_debug = RTG.NMG_debug;
		break;
	    case 'e':		/* Error file name. */
		error_file = bu_optarg;
		break;
	    case 'i':
		inches = 1;
		break;
	    default:
		usage(argv[0]);
	}
    }

    if (bu_optind+1 >= argc)
	usage(argv[0]);

    if (!output_file) {
	fp = stdout;
	setmode(fileno(fp), O_BINARY);
    } else {
	/* Open output file */
	if ((fp=fopen(output_file, "wb+")) == NULL) {
	    perror(argv[0]);
	    bu_exit(1, "Cannot open output file (%s) for writing\n", output_file);
	}
    }

    /* Open g-acad error log file */
    if (!error_file) {
	fpe = stderr;
	setmode(fileno(fpe), O_BINARY);
    } else if ((fpe=fopen(error_file, "wb")) == NULL) {
	perror(argv[0]);
	bu_exit(1, "Cannot open output file (%s) for writing\n", error_file);
    }


    /* Open BRL-CAD database */
    argc -= bu_optind;
    argv += bu_optind;
    if ((dbip = db_open(argv[0], DB_OPEN_READONLY)) == DBI_NULL) {
	perror(argv[0]);
	bu_exit(1, "Cannot open geometry database file (%s)\n", argv[0]);
    }
    if (db_dirbuild(dbip)) {
	bu_exit(1, "db_dirbuild failed\n");
    }

    BN_CK_TOL(tree_state.ts_tol);
    RT_CK_TESS_TOL(tree_state.ts_ttol);

    fprintf(fpe, "Model: %s\n", argv[0]);
    fprintf(fpe, "Objects:");
    for (i=1; i<argc; i++)
	fprintf(fpe, " %s", argv[i]);
    fprintf(fpe, "\nTessellation tolerances:\n\tabs = %g mm\n\trel = %g\n\tnorm = %g\n",
	    tree_state.ts_ttol->abs, tree_state.ts_ttol->rel, tree_state.ts_ttol->norm);
    fprintf(fpe, "Calculational tolerances:\n\tdist = %g mm perp = %g\n",
	    tree_state.ts_tol->dist, tree_state.ts_tol->perp);

    bu_log("Model: %s\n", argv[0]);
    bu_log("Objects:");
    for (i=1; i<argc; i++)
	bu_log(" %s", argv[i]);
    bu_log("\nTessellation tolerances:\n\tabs = %g mm\n\trel = %g\n\tnorm = %g\n",
	   tree_state.ts_ttol->abs, tree_state.ts_ttol->rel, tree_state.ts_ttol->norm);
    bu_log("Calculational tolerances:\n\tdist = %g mm perp = %g\n",
	   tree_state.ts_tol->dist, tree_state.ts_tol->perp);

/* Write out ACAD facet header */
    if (inches)
	fprintf(fp, "BRL-CAD generated ACAD FACET FILE (Units in)\n");
    else
	fprintf(fp, "BRL-CAD generated ACAD FACET FILE (Units mm)\n");

/* Generate space for number of facet entities, will write over later */

    fprintf(fp, "               ");

    /* Walk indicated tree(s).  Each region will be output separately */
    (void) db_walk_tree(dbip, argc-1, (const char **)(argv+1),
			1,			/* ncpu */
			&tree_state,
			0,			/* take all regions */
			do_region_end,
			nmg_booltree_leaf_tess,
			(void *)NULL);	/* in librt/nmg_bool.c */

    percent = 0;
    if (regions_tried>0) {
	percent = ((double)regions_converted * 100) / regions_tried;
	printf("Tried %d regions, %d converted to NMG's successfully.  %g%%\n",
	       regions_tried, regions_converted, percent);
    }
    percent = 0;

    if (regions_tried > 0) {
	percent = ((double)regions_written * 100) / regions_tried;
	printf("                  %d triangulated successfully. %g%%\n",
	       regions_written, percent);
    }

    bu_log("%ld triangles written\n", tot_polygons);
    fprintf(fpe, "%ld triangles written\n", tot_polygons);

    /* Write out number of facet entities to .facet file */

    rewind(fp);
    bu_fseek(fp, 46, 0); /* Re-position pointer to 2nd line */
    fprintf(fp, "%d\n", regions_written); /* Write out number of regions */
    fclose(fp);

    /* Release dynamic storage */
    nmg_km(the_model);
    rt_vlist_cleanup();
    db_close(dbip);

    return 0;
}
/*
 * 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 = NULL;
    struct bu_list vhead;
    /* static due to longjmp */
    static struct nmgregion *r = 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 (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++;

    /* do the deed */
    ret_tree = process_region(pathp, curtree, tsp);

    if (ret_tree)
	r = ret_tree->tr_d.td_r;
    else {
	if (verbose) {
	    printf("\tNothing left of this region after Boolean evaluation\n");
	    fprintf(fpe, "WARNING: Nothing left after Boolean evaluation: %s\n",
		    db_path_to_string(pathp));
	    fflush(fpe);
	}
	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) {
	    if (!BU_SETJUMP) {
		/* try */

		/* Write the region to the TANKILL file */
		nmg_to_acad(r, pathp, tsp->ts_regionid);
		regions_written++;

	    } else {
		/* catch */

		char *sofar;

		BU_UNSETJUMP;

		sofar = db_path_to_string(pathp);
		bu_free((char *)sofar, "sofar");

		/* Sometimes the NMG library adds debugging bits when
		 * it detects an internal error, before bombing out.
		 */
		RTG.NMG_debug = NMG_debug;	/* restore mode */

		/* 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();

		/* FIXME: leaking memory with curtree */

		return TREE_NULL;
	    } BU_UNSETJUMP;
	}

	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.
     */

    if (regions_tried>0) {
	float npercent, tpercent;

	npercent = (float)(regions_converted * 100) / regions_tried;
	tpercent = (float)(regions_written * 100) / regions_tried;
	printf("Tried %d regions, %d conv. to NMG's %d conv. to tri. nmgper = %.2f%% triper = %.2f%% \n",
	       regions_tried, regions_converted, regions_written, npercent, tpercent);
    }

    BU_ALLOC(curtree, union tree);
    RT_TREE_INIT(curtree);
    curtree->tr_op = OP_NOP;

    return curtree;
}
Beispiel #3
0
/**
 * If there is no ve_dist structure for this edge, compute one and
 * add it to the list.
 *
 * Sort an edge_info structure into the loops list of edgeuse status
 */
static struct edge_info *
nmg_class_pt_eu(struct fpi *fpi, struct edgeuse *eu, struct edge_info *edge_list, const int in_or_out_only)
{
    struct bn_tol tmp_tol;
    struct edgeuse *next_eu;
    struct ve_dist *ved, *ed;
    struct edge_info *ei_p;
    struct edge_info *ei;
    pointp_t eu_pt;
    vect_t left;
    vect_t v_to_pt;
    int found_data = 0;

    NMG_CK_FPI(fpi);
    BN_CK_TOL(fpi->tol);

    if (RTG.NMG_debug & DEBUG_PT_FU) {
	bu_log("pt (%g %g %g) vs_edge (%g %g %g) (%g %g %g) (eu=%p)\n",
	       V3ARGS(fpi->pt),
	       V3ARGS(eu->vu_p->v_p->vg_p->coord),
	       V3ARGS(eu->eumate_p->vu_p->v_p->vg_p->coord), (void *)eu);
    }

    /* we didn't find a ve_dist structure for this edge, so we'll
     * have to do the calculations.
     */
    tmp_tol = (*fpi->tol);
    if (in_or_out_only) {
	tmp_tol.dist = 0.0;
	tmp_tol.dist_sq = 0.0;
    }

    BU_ALLOC(ved, struct ve_dist);
    ved->magic_p = &eu->e_p->magic;
    ved->status = bn_distsq_pt3_lseg3(&ved->dist,
				      eu->vu_p->v_p->vg_p->coord,
				      eu->eumate_p->vu_p->v_p->vg_p->coord,
				      fpi->pt,
				      &tmp_tol);
    ved->v1 = eu->vu_p->v_p;
    ved->v2 = eu->eumate_p->vu_p->v_p;
    BU_LIST_MAGIC_SET(&ved->l, NMG_VE_DIST_MAGIC);
    BU_LIST_APPEND(&fpi->ve_dh, &ved->l);
    eu_pt = ved->v1->vg_p->coord;

    if (RTG.NMG_debug & DEBUG_PT_FU) {
	bu_log("nmg_class_pt_eu: status for eu %p (%g %g %g)<->(%g %g %g) vs pt (%g %g %g) is %d\n",
	       (void *)eu, V3ARGS(eu->vu_p->v_p->vg_p->coord),
	       V3ARGS(eu->eumate_p->vu_p->v_p->vg_p->coord),
	       V3ARGS(fpi->pt), ved->status);
	bu_log("\tdist = %g\n", ved->dist);
    }


    /* Add a struct for this edgeuse to the loop's list of dist-sorted
     * edgeuses.
     */
    BU_ALLOC(ei, struct edge_info);
    ei->ved_p = ved;
    ei->eu_p = eu;
    BU_LIST_MAGIC_SET(&ei->l, NMG_EDGE_INFO_MAGIC);

    /* compute the status (ei->status) of the point WRT this edge */

    switch (ved->status) {
	case 0: /* pt is on the edge(use) */
	    ei->nmg_class = NMG_CLASS_AonBshared;
	    if (fpi->eu_func &&
		(fpi->hits == NMG_FPI_PERUSE ||
		 (fpi->hits == NMG_FPI_PERGEOM && !found_data))) {
		/* need to cast eu_func pointer for actual use as a function */
		void (*cfp)(struct edgeuse *, point_t, const char*);
		cfp = (void (*)(struct edgeuse *, point_t, const char *))fpi->eu_func;
		cfp(eu, fpi->pt, fpi->priv);
	    }
	    break;
	case 1:	/* within tolerance of endpoint at ved->v1 */
	    ei->nmg_class = NMG_CLASS_AonBshared;
	    /* add an entry for the vertex in the edge list so that
	     * other uses of this vertex will claim the point is within
	     * tolerance without re-computing
	     */
	    BU_ALLOC(ed, struct ve_dist);
	    ed->magic_p = &ved->v1->magic;
	    ed->status = ved->status;
	    ed->v1 = ed->v2 = ved->v1;

	    BU_LIST_MAGIC_SET(&ed->l, NMG_VE_DIST_MAGIC);
	    BU_LIST_APPEND(&fpi->ve_dh, &ed->l);

	    if (fpi->vu_func &&
		(fpi->hits == NMG_FPI_PERUSE ||
		 (fpi->hits == NMG_FPI_PERGEOM && !found_data))) {
		/* need to cast vu_func pointer for actual use as a function */
		void (*cfp)(struct vertexuse *, point_t, const char*);
		cfp = (void (*)(struct vertexuse *, point_t, const char *))fpi->vu_func;
		cfp(eu->vu_p, fpi->pt, fpi->priv);
	    }

	    break;
	case 2:	/* within tolerance of endpoint at ved->v2 */
	    ei->nmg_class = NMG_CLASS_AonBshared;
	    /* add an entry for the vertex in the edge list so that
	     * other uses of this vertex will claim the point is within
	     * tolerance without re-computing
	     */
	    BU_ALLOC(ed, struct ve_dist);
	    ed->magic_p = &ved->v2->magic;
	    ed->status = ved->status;
	    ed->v1 = ed->v2 = ved->v2;

	    BU_LIST_MAGIC_SET(&ed->l, NMG_VE_DIST_MAGIC);
	    BU_LIST_APPEND(&fpi->ve_dh, &ed->l);
	    if (fpi->vu_func &&
		(fpi->hits == NMG_FPI_PERUSE ||
		 (fpi->hits == NMG_FPI_PERGEOM && !found_data))) {
		/* need to cast vu_func pointer for actual use as a function */
		void (*cfp)(struct vertexuse *, point_t, const char*);
		cfp = (void (*)(struct vertexuse *, point_t, const char *))fpi->vu_func;
		cfp(eu->eumate_p->vu_p, fpi->pt, fpi->priv);
	    }
	    break;

	case 3: /* PCA of pt on line is within tolerance of ved->v1 of segment */
	    ei->nmg_class = nmg_class_pt_euvu(fpi->pt, eu, fpi->tol);
	    if (ei->nmg_class == NMG_CLASS_Unknown)
		ei->ved_p->dist = MAX_FASTF;
	    break;
	case 4: /* PCA of pt on line is within tolerance of ved->v2 of segment */
	    next_eu = BU_LIST_PNEXT_CIRC(edgeuse, &eu->l);
	    ei->nmg_class = nmg_class_pt_euvu(fpi->pt, next_eu, fpi->tol);
	    if (ei->nmg_class == NMG_CLASS_Unknown)
		ei->ved_p->dist = MAX_FASTF;
	    break;

	case 5: /* PCA is along length of edge, but point is NOT on edge. */
	    if (nmg_find_eu_left_non_unit(left, eu))
		bu_bomb("can't find left vector\n");
	    /* take dot product of v->pt vector with left to determine
	     * if pt is inside/left of edge
	     */
	    VSUB2(v_to_pt, fpi->pt, eu_pt);
	    if (VDOT(v_to_pt, left) > -SMALL_FASTF)
		ei->nmg_class = NMG_CLASS_AinB;
	    else
		ei->nmg_class = NMG_CLASS_AoutB;
	    break;
	default:
	    bu_log("%s:%d status = %d\n", __FILE__, __LINE__, ved->status);
	    bu_bomb("Why did this happen?");
	    break;
    }


    if (RTG.NMG_debug & DEBUG_PT_FU) {
	bu_log("pt @ dist %g from edge classed %s vs edge\n",
	       ei->ved_p->dist, nmg_class_name(ei->nmg_class));
/* pl_pt_e(fpi, ei); */
    }

    /* now that it's complete, add ei to the edge list */
    for (BU_LIST_FOR(ei_p, edge_info, &edge_list->l)) {
	/* if the distance to this edge is smaller, or
	 * if the distance is the same & the edge is the same
	 * Insert edge_info struct here in list
	 */
	if (ved->dist < ei_p->ved_p->dist
	    || (ZERO(ved->dist - ei_p->ved_p->dist)
		&& ei_p->ved_p->magic_p == ved->magic_p))
	{
	    break;
	}
    }

    BU_LIST_INSERT(&ei_p->l, &ei->l);
    return ei;
}
Beispiel #4
0
int
nmg_class_pt_euvu(const fastf_t *pt, struct edgeuse *eu_in, const struct bn_tol *tol)
{
    struct loopuse *lu;
    struct edgeuse *prev_eu;
    struct edgeuse *eu;
    struct vertex *v0, *v1, *v2;
    vect_t left;
    vect_t eu_dir;
    vect_t other_eudir;
    vect_t pt_dir;
    fastf_t xo, yo;
    fastf_t xpt, ypt;
    fastf_t len;
    int quado, quadpt;
    int nmg_class = NMG_CLASS_Unknown;
    int eu_is_crack = 0;
    int prev_eu_is_crack = 0;

    NMG_CK_EDGEUSE(eu_in);
    BN_CK_TOL(tol);

    eu = eu_in;

    if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU))
	bu_log("nmg_class_pt_euvu((%g %g %g), eu=%p)\n", V3ARGS(pt), (void *)eu);

    if (UNLIKELY(*eu->up.magic_p != NMG_LOOPUSE_MAGIC)) {
	bu_log("nmg_class_pt_euvu() called with eu (%p) that isn't part of a loop\n", (void *)eu);
	bu_bomb("nmg_class_pt_euvu() called with eu that isn't part of a loop");
    }
    lu = eu->up.lu_p;
    NMG_CK_LOOPUSE(lu);

    eu_is_crack = nmg_eu_is_part_of_crack(eu);

    prev_eu = BU_LIST_PPREV_CIRC(edgeuse, &eu->l);

    prev_eu_is_crack = nmg_eu_is_part_of_crack(prev_eu);

    /* if both EU's are cracks, we cannot classify */
    if (eu_is_crack && prev_eu_is_crack)
	return NMG_CLASS_Unknown;

    if (eu_is_crack) {
	struct edgeuse *eu_test;
	int done = 0;

	if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU))
	    bu_log("nmg_class_pt_euvu: eu %p is a crack\n", (void *)eu);

	/* find next eu from this vertex that is not a crack */
	eu_test = BU_LIST_PNEXT_CIRC(edgeuse, &eu->l);
	while (!done) {
	    while (eu_test->vu_p->v_p != eu->vu_p->v_p && eu_test != eu)
		eu_test = BU_LIST_PNEXT_CIRC(edgeuse, &eu_test->l);

	    if (eu_test == eu)
		done = 1;

	    if (!nmg_eu_is_part_of_crack(eu_test))
		done = 1;

	    if (!done)
		eu_test = BU_LIST_PNEXT_CIRC(edgeuse, &eu_test->l);
	}

	if (eu_test == eu) /* can't get away from crack */
	    return NMG_CLASS_Unknown;
	else
	    eu = eu_test;

	if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU))
	    bu_log("\tUsing eu %p instead\n", (void *)eu);
    }

    if (prev_eu_is_crack) {
	struct edgeuse *eu_test;
	int done = 0;

	if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU))
	    bu_log("nmg_class_pt_euvu: prev_eu (%p) is a crack\n", (void *)prev_eu);

	/* find previous eu ending at this vertex that is not a crack */
	eu_test = BU_LIST_PPREV_CIRC(edgeuse, &prev_eu->l);
	while (!done) {
	    while (eu_test->eumate_p->vu_p->v_p != eu->vu_p->v_p && eu_test != prev_eu)
		eu_test = BU_LIST_PPREV_CIRC(edgeuse, &eu_test->l);

	    if (eu_test == prev_eu)
		done = 1;

	    if (!nmg_eu_is_part_of_crack(eu_test))
		done = 1;

	    if (!done)
		eu_test = BU_LIST_PPREV_CIRC(edgeuse, &eu_test->l);
	}

	if (eu_test == prev_eu) /* can't get away from crack */
	    return NMG_CLASS_Unknown;
	else
	    prev_eu = eu_test;

	if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU))
	    bu_log("\tUsing prev_eu %p instead\n", (void *)prev_eu);
    }

    /* left is the Y-axis of our XY-coordinate system */
    if (UNLIKELY(nmg_find_eu_leftvec(left, eu))) {
	bu_log("nmg_class_pt_euvu: nmg_find_eu_leftvec() for eu=%p failed!\n", (void *)eu);
	bu_bomb("nmg_class_pt_euvu: nmg_find_eu_leftvec() failed!");
    }

    if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU))
	bu_log("\tprev_eu = %p, left = (%g %g %g)\n", (void *)prev_eu, V3ARGS(left));

    /* v0 is the origin of the XY-coordinate system */
    v0 = eu->vu_p->v_p;
    NMG_CK_VERTEX(v0);

    /* v1 is on the X-axis */
    v1 = eu->eumate_p->vu_p->v_p;
    NMG_CK_VERTEX(v1);

    /* v2 determines angle prev_eu makes with X-axis */
    v2 = prev_eu->vu_p->v_p;
    NMG_CK_VERTEX(v2);

    if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU))
	bu_log("\tv0=%p, v1=%p, v2=%p\n", (void *)v0, (void *)v1, (void *)v2);

    /* eu_dir is our X-direction */
    VSUB2(eu_dir, v1->vg_p->coord, v0->vg_p->coord);

    /* other_eudir is direction along the previous EU (from origin) */
    VSUB2(other_eudir, v2->vg_p->coord, v0->vg_p->coord);

    if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU))
	bu_log("\teu_dir=(%g %g %g), other_eudir=(%g %g %g)\n", V3ARGS(eu_dir), V3ARGS(other_eudir));

    /* get X and Y components for other_eu */
    xo = VDOT(eu_dir, other_eudir);
    yo = VDOT(left, other_eudir);

    /* which quadrant does this XY point lie in */
    quado = Quadrant(xo, yo);

    if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU))
	bu_log("\txo=%g, yo=%g, quadrant=%d\n", xo, yo, quado);

    /* get direction to PT from origin */
    VSUB2(pt_dir, pt, v0->vg_p->coord);

    if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU))
	bu_log("\tpt_dir=(%g %g %g)\n", V3ARGS(pt_dir));

    /* get X and Y components for PT */
    xpt = VDOT(eu_dir, pt_dir);
    ypt = VDOT(left, pt_dir);

    /* which quadrant does this XY point lie in */
    quadpt = Quadrant(xpt, ypt);

    if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU))
	bu_log("\txpt=%g, ypt=%g, quadrant=%d\n", xpt, ypt, quadpt);

    /* do a quadrant comparison first (cheap!!!) */
    if (quadpt < quado)
	return NMG_CLASS_AinB;

    if (quadpt > quado)
	return NMG_CLASS_AoutB;

    /* both are in the same quadrant, need to normalize the coordinates */
    len = sqrt(xo*xo + yo*yo);
    xo = xo/len;
    yo = yo/len;

    len = sqrt(xpt*xpt + ypt*ypt);
    xpt = xpt/len;
    ypt = ypt/len;

    if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU))
	bu_log("\tNormalized xo, yo=(%g %g), xpt, ypt=(%g %g)\n", xo, yo, xpt, ypt);

    switch (quadpt) {
	case 1:
	    if (xpt >= xo && ypt <= yo)
		nmg_class = NMG_CLASS_AinB;
	    else
		nmg_class = NMG_CLASS_AoutB;
	    break;
	case 2:
	    if (xpt >= xo && ypt >= yo)
		nmg_class = NMG_CLASS_AinB;
	    else
		nmg_class = NMG_CLASS_AoutB;
	    break;
	case 3:
	    if (xpt <= xo && ypt >= yo)
		nmg_class = NMG_CLASS_AinB;
	    else
		nmg_class = NMG_CLASS_AoutB;
	    break;
	case 4:
	    if (xpt <= xo && ypt <= yo)
		nmg_class = NMG_CLASS_AinB;
	    else
		nmg_class = NMG_CLASS_AoutB;
	    break;
	default:
	    bu_log("This can't happen (illegal quadrant %d)\n", quadpt);
	    bu_bomb("This can't happen (illegal quadrant)\n");
	    break;
    }
    if (UNLIKELY(RTG.NMG_debug & DEBUG_PT_FU))
	bu_log("returning %s\n", nmg_class_name(nmg_class));

    return nmg_class;
}
Beispiel #5
0
/**
 * Find the square of the distance from a point P to a line segment described
 * by the two endpoints A and B.
 *
 *			P
 *		       *
 *		      /.
 *		     / .
 *		    /  .
 *		   /   . (dist)
 *		  /    .
 *		 /     .
 *		*------*--------*
 *		A      PCA	B
 *
 * There are six distinct cases, with these return codes -
 *	0	P is within tolerance of lseg AB.  *dist =  0.
 *	1	P is within tolerance of point A.  *dist = 0.
 *	2	P is within tolerance of point B.  *dist = 0.
 *	3	PCA is within tolerance of A. *dist = |P-A|**2.
 *	4	PCA is within tolerance of B. *dist = |P-B|**2.
 *	5	P is "above/below" lseg AB.  *dist=|PCA-P|**2.
 *
 * This routine was formerly called bn_dist_pt_lseg().
 * This is a special version that returns the square of the distance
 * and does not actually calculate PCA.
 *
 */
int
bn_distsq_pt3_lseg3(fastf_t *dist, const fastf_t *a, const fastf_t *b, const fastf_t *p, const struct bn_tol *tol)
{
    vect_t PtoA;		/* P-A */
    vect_t PtoB;		/* P-B */
    vect_t AtoB;		/* B-A */
    fastf_t P_A_sq;		/* |P-A|**2 */
    fastf_t P_B_sq;		/* |P-B|**2 */
    fastf_t B_A_sq;		/* |B-A|**2 */
    fastf_t t;		/* distance squared along ray of projection of P */
    fastf_t dot;

    BN_CK_TOL(tol);

    /* Check proximity to endpoint A */
    VSUB2(PtoA, p, a);
    P_A_sq = MAGSQ(PtoA);
    if (P_A_sq < tol->dist_sq) {
	/* P is within the tol->dist radius circle around A */
	*dist = 0.0;
	return 1;
    }

    /* Check proximity to endpoint B */
    VSUB2(PtoB, p, b);
    P_B_sq = MAGSQ(PtoB);
    if (P_B_sq < tol->dist_sq) {
	/* P is within the tol->dist radius circle around B */
	*dist = 0.0;
	return 2;
    }

    VSUB2(AtoB, b, a);
    B_A_sq = MAGSQ(AtoB);

    /* compute distance squared (in actual units) along line to PROJECTION of
     * point p onto the line: point pca
     */
    dot = VDOT(PtoA, AtoB);
    t = dot * dot / B_A_sq;

    if (t < tol->dist_sq) {
	/* PCA is at A */
	*dist = P_A_sq;
	return 3;
    }

    if (dot < -SMALL_FASTF && t > tol->dist_sq) {
	/* P is "left" of A */
	*dist = P_A_sq;
	return 3;
    }
    if (t < (B_A_sq - tol->dist_sq)) {
	/* PCA falls between A and B */
	register fastf_t dsq;

	/* Find distance from PCA to line segment (Pythagorus) */
	dsq = P_A_sq - t;
	if (dsq < tol->dist_sq) {
	    /* PCA is on lseg */
	    *dist = 0.0;
	    return 0;
	}

	/* P is above or below lseg */
	*dist = dsq;
	return 5;
    }

    /* P is "right" of B */
    *dist = P_B_sq;
    return 4;
}
Beispiel #6
0
/**
 * This is the gist for what is going on (not verified):
 *
 * 1. initialize tree_state (db_tree_state)
 * 2. Deal with command line arguments. Strip off everything but regions for processing.
 * 3. Open geometry (.g) file and build directory db_dirbuild
 * 4. db_walk_tree (get_layer) for layer names only
 * 5. Initialize tree_state
 * 6. Initialize model (nmg)\
 * 7. db_walk_tree (gcv_region_end)
 * 8. Cleanup
 */
int
main(int argc, char *argv[])
{
    int c;
    double percent;

    bu_setlinebuf(stderr);

    tree_state = rt_initial_tree_state;	/* struct copy */
    tree_state.ts_tol = &tol;
    tree_state.ts_ttol = &ttol;
    tree_state.ts_m = &the_model;

    /* Set up tessellation tolerance defaults */
    ttol.magic = RT_TESS_TOL_MAGIC;
    /* Defaults, updated by command line options. */
    ttol.abs = 0.0;
    ttol.rel = 0.01;
    ttol.norm = 0.0;

    /* Set up calculation tolerance defaults */
    /* FIXME: These need to be improved */
    tol.magic = BN_TOL_MAGIC;
    tol.dist = 0.0005;
    tol.dist_sq = tol.dist * tol.dist;
    tol.perp = 1e-6;
    tol.para = 1 - tol.perp;

    /* init resources we might need */
    rt_init_resource(&rt_uniresource, 0, NULL);

    BU_LIST_INIT(&RTG.rtg_vlfree);	/* for vlist macros */

    /* Get command line arguments. */
    while ((c = bu_getopt(argc, argv, "a:n:o:pr:vx:D:P:X:ih?")) != -1) {
	switch (c) {
	    case 'a':		/* Absolute tolerance. */
		ttol.abs = atof(bu_optarg);
		ttol.rel = 0.0;
		break;
	    case 'n':		/* Surface normal tolerance. */
		ttol.norm = atof(bu_optarg);
		ttol.rel = 0.0;
		break;
	    case 'o':		/* Output file name. */
		output_file = bu_optarg;
		break;
	    case 'p':
		polyface_mesh = 1;
		break;
	    case 'r':		/* Relative tolerance. */
		ttol.rel = atof(bu_optarg);
		break;
	    case 'v':
		verbose++;
		break;
	    case 'P':
		ncpu = atoi(bu_optarg);
		break;
	    case 'x':
		sscanf(bu_optarg, "%x", (unsigned int *)&RTG.debug);
		break;
	    case 'D':
		tol.dist = atof(bu_optarg);
		tol.dist_sq = tol.dist * tol.dist;
		rt_pr_tol(&tol);
		break;
	    case 'X':
		sscanf(bu_optarg, "%x", (unsigned int *)&RTG.NMG_debug);
		NMG_debug = RTG.NMG_debug;
		break;
	    case 'i':
		inches = 1;
		break;
	    default:
		usage(argv[0]);
		bu_exit(1, "%s\n", brlcad_ident("BRL-CAD to DXF Exporter"));
		break;
	}
    }

    if (bu_optind+1 >= argc) {
	usage(argv[0]);
	bu_exit(1, "%s\n", brlcad_ident("BRL-CAD to DXF Exporter"));
    }

    if (!output_file) {
	fp = stdout;
	setmode(fileno(fp), O_BINARY);
    } else {
	/* Open output file */
	if ((fp=fopen(output_file, "w+b")) == NULL) {
	    perror(argv[0]);
	    bu_exit(1, " Cannot open output file (%s) for writing\n", output_file);
	}
    }

    /* Open BRL-CAD database */
    argc -= bu_optind;
    argv += bu_optind;
    if ((dbip = db_open(argv[0], DB_OPEN_READONLY)) == DBI_NULL) {
	perror(argv[0]);
	bu_exit(1, "Unable to open geometry database file (%s)\n", argv[0]);
    }

    if (db_dirbuild(dbip)) {
	bu_exit(1, "db_dirbuild failed\n");
    }

    BN_CK_TOL(tree_state.ts_tol);
    RT_CK_TESS_TOL(tree_state.ts_ttol);

    if (verbose) {
	int i;

	bu_log("Model: %s\n", argv[0]);
	bu_log("Objects:");
	for (i = 1; i < argc; i++)
	    bu_log(" %s", argv[i]);
	bu_log("\nTessellation tolerances:\n\tabs = %g mm\n\trel = %g\n\tnorm = %g\n",
		tree_state.ts_ttol->abs, tree_state.ts_ttol->rel, tree_state.ts_ttol->norm);
	bu_log("Calculational tolerances:\n\tdist = %g mm perp = %g\n",
		tree_state.ts_tol->dist, tree_state.ts_tol->perp);
    }

    /* output DXF header and start of TABLES section */
    fprintf(fp,
	    "0\nSECTION\n2\nHEADER\n999\n%s\n0\nENDSEC\n0\nSECTION\n2\nTABLES\n0\nTABLE\n2\nLAYER\n",
	    argv[argc-1]);

    /* Walk indicated tree(s) just for layer names to put in TABLES section */
    (void)db_walk_tree(dbip, argc-1, (const char **)(argv+1),
		       1,			/* ncpu */
		       &tree_state,
		       0,			/* take all regions */
		       get_layer,
		       NULL,
		       (void *)NULL);	/* in librt/nmg_bool.c */

    /* end of layers section, start of ENTITIES SECTION */
    fprintf(fp, "0\nENDTAB\n0\nENDSEC\n0\nSECTION\n2\nENTITIES\n");

    /* Walk indicated tree(s).  Each region will be output separately */
    tree_state = rt_initial_tree_state;	/* struct copy */
    tree_state.ts_tol = &tol;
    tree_state.ts_ttol = &ttol;
    /* make empty NMG model */
    the_model = nmg_mm();
    tree_state.ts_m = &the_model;
    (void) db_walk_tree(dbip, argc-1, (const char **)(argv+1),
			1,			/* ncpu */
			&tree_state,
			0,			/* take all regions */
			gcv_region_end,
			nmg_booltree_leaf_tess,
			(void *)&gcvwriter);	/* callback for gcv_region_end */

    percent = 0;
    if (regions_tried>0) {
	percent = ((double)regions_converted * 100) / regions_tried;
	if (verbose)
	    bu_log("Tried %d regions, %d converted to NMG's successfully.  %g%%\n",
		   regions_tried, regions_converted, percent);
    }
    percent = 0;

    if (regions_tried > 0) {
	percent = ((double)regions_written * 100) / regions_tried;
	if (verbose)
	    bu_log("                  %d triangulated successfully. %g%%\n",
		    regions_written, percent);
    }

    bu_log("%ld triangles written\n", (long int)tot_polygons);

    fprintf(fp, "0\nENDSEC\n0\nEOF\n");

    if (output_file) {
	fclose(fp);
    }

    /* Release dynamic storage */
    nmg_km(the_model);
    rt_vlist_cleanup();
    db_close(dbip);

    return 0;
}