Exemple #1
0
/**
 * Calculate a bounding RPP for an ARBN
 */
int
rt_arbn_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *UNUSED(tol)) {
    size_t i, j, k;
    struct rt_arbn_internal *aip;
    RT_CK_DB_INTERNAL(ip);
    aip = (struct rt_arbn_internal *)ip->idb_ptr;
    RT_ARBN_CK_MAGIC(aip);

    VSETALL((*min), INFINITY);
    VSETALL((*max), -INFINITY);

    /* Discover all vertices, use to calculate RPP */
    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 (((dot) <= -SMALL_FASTF) ? (NEAR_EQUAL((dot), -1.0,  RT_DOT_TOL)) : (NEAR_EQUAL((dot), 1.0, RT_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] > RT_LEN_TOL) {
			next_k = 1;
			break;
		    }
		}
		if (next_k != 0) continue;

		VMINMAX((*min), (*max), pt);
	    }
	}
    }

    return 0;
}
Exemple #2
0
/*
 * Default keypoint in model space is established in "pt". Returns
 * GED_ERROR if unable to determine a keypoint, otherwise returns
 * GED_OK.
 */
int
_ged_get_solid_keypoint(struct ged *const gedp,
			fastf_t *const pt,
			const struct rt_db_internal *const ip,
			const fastf_t *const mat)
{
    point_t mpt;

    RT_CK_DB_INTERNAL(ip);

    switch (ip->idb_type) {
	case ID_CLINE:
	    {
		struct rt_cline_internal *cli =
		    (struct rt_cline_internal *)ip->idb_ptr;

		RT_CLINE_CK_MAGIC(cli);

		VMOVE(mpt, cli->v);
		break;
	    }
	case ID_PARTICLE:
	    {
		struct rt_part_internal *part =
		    (struct rt_part_internal *)ip->idb_ptr;

		RT_PART_CK_MAGIC(part);

		VMOVE(mpt, part->part_V);
		break;
	    }
	case ID_PIPE:
	    {
		struct rt_pipe_internal *pipeip;
		struct wdb_pipept *pipe_seg;

		pipeip = (struct rt_pipe_internal *)ip->idb_ptr;

		RT_PIPE_CK_MAGIC(pipeip);

		pipe_seg = BU_LIST_FIRST(wdb_pipept, &pipeip->pipe_segs_head);
		VMOVE(mpt, pipe_seg->pp_coord);
		break;
	    }
	case ID_METABALL:
	    {
		struct rt_metaball_internal *metaball =
		    (struct rt_metaball_internal *)ip->idb_ptr;
		struct wdb_metaballpt *metaballpt;

		RT_METABALL_CK_MAGIC(metaball);

		VSETALL(mpt, 0.0);
		metaballpt = BU_LIST_FIRST(wdb_metaballpt,
					   &metaball->metaball_ctrl_head);
		VMOVE(mpt, metaballpt->coord);
		break;
	    }
	case ID_ARBN:
	    {
		struct rt_arbn_internal *arbn =
		    (struct rt_arbn_internal *)ip->idb_ptr;
		size_t i, j, k;
		int good_vert = 0;

		RT_ARBN_CK_MAGIC(arbn);
		for (i = 0; i < arbn->neqn; i++) {
		    for (j = i + 1; j < arbn->neqn; j++) {
			for (k = j + 1; k < arbn->neqn; k++) {
			    if (!bn_mkpoint_3planes(mpt, arbn->eqn[i],
						    arbn->eqn[j],
						    arbn->eqn[k])) {
				size_t l;

				good_vert = 1;
				for (l = 0; l < arbn->neqn; l++) {
				    if (l == i || l == j || l == k)
					continue;

				    if (DIST_PT_PLANE(mpt,
					arbn->eqn[l]) >
					gedp->ged_wdbp->wdb_tol.dist) {
					good_vert = 0;
					break;
				    }
				}

				if (good_vert)
				    break;
			    }
			}
			if (good_vert)
			    break;
		    }
		    if (good_vert)
			break;
		}

		break;
	    }
	case ID_EBM:
	    {
		struct rt_ebm_internal *ebm =
		    (struct rt_ebm_internal *)ip->idb_ptr;
		point_t pnt;

		RT_EBM_CK_MAGIC(ebm);

		VSETALL(pnt, 0.0);
		MAT4X3PNT(mpt, ebm->mat, pnt);
		break;
	    }
	case ID_BOT:
	    {
		struct rt_bot_internal *bot =
		    (struct rt_bot_internal *)ip->idb_ptr;

		    VMOVE(mpt, bot->vertices);
		break;
	    }
	case ID_DSP:
	    {
		struct rt_dsp_internal *dsp =
		    (struct rt_dsp_internal *)ip->idb_ptr;
		point_t pnt;

		RT_DSP_CK_MAGIC(dsp);

		VSETALL(pnt, 0.0);
		MAT4X3PNT(mpt, dsp->dsp_stom, pnt);
		break;
	    }
	case ID_HF:
	    {
		struct rt_hf_internal *hf =
		    (struct rt_hf_internal *)ip->idb_ptr;

		RT_HF_CK_MAGIC(hf);

		VMOVE(mpt, hf->v);
		break;
	    }
	case ID_VOL:
	    {
		struct rt_vol_internal *vol =
		    (struct rt_vol_internal *)ip->idb_ptr;
		point_t pnt;

		RT_VOL_CK_MAGIC(vol);

		VSETALL(pnt, 0.0);
		MAT4X3PNT(mpt, vol->mat, pnt);
		break;
	    }
	case ID_HALF:
	    {
		struct rt_half_internal *haf =
		    (struct rt_half_internal *)ip->idb_ptr;
		RT_HALF_CK_MAGIC(haf);

		VSCALE(mpt, haf->eqn, haf->eqn[H]);
		break;
	    }
	case ID_ARB8:
	    {
		struct rt_arb_internal *arb =
		    (struct rt_arb_internal *)ip->idb_ptr;
		RT_ARB_CK_MAGIC(arb);

		VMOVE(mpt, arb->pt[0]);
		break;
	    }
	case ID_ELL:
	case ID_SPH:
	    {
		struct rt_ell_internal *ell =
		    (struct rt_ell_internal *)ip->idb_ptr;
		RT_ELL_CK_MAGIC(ell);

		VMOVE(mpt, ell->v);
		break;
	    }
	case ID_SUPERELL:
	    {
		struct rt_superell_internal *superell =
		    (struct rt_superell_internal *)ip->idb_ptr;
		RT_SUPERELL_CK_MAGIC(superell);

		VMOVE(mpt, superell->v);
		break;
	    }
	case ID_TOR:
	    {
		struct rt_tor_internal *tor =
		    (struct rt_tor_internal *)ip->idb_ptr;
		RT_TOR_CK_MAGIC(tor);

		VMOVE(mpt, tor->v);
		break;
	    }
	case ID_TGC:
	case ID_REC:
	    {
		struct rt_tgc_internal *tgc =
		    (struct rt_tgc_internal *)ip->idb_ptr;
		RT_TGC_CK_MAGIC(tgc);

		VMOVE(mpt, tgc->v);
		break;
	    }
	case ID_GRIP:
	    {
		struct rt_grip_internal *gip =
		    (struct rt_grip_internal *)ip->idb_ptr;
		RT_GRIP_CK_MAGIC(gip);
		VMOVE(mpt, gip->center);
		break;
	    }
	case ID_ARS:
	    {
		struct rt_ars_internal *ars =
		    (struct rt_ars_internal *)ip->idb_ptr;
		RT_ARS_CK_MAGIC(ars);

		VMOVE(mpt, &ars->curves[0][0]);
		break;
	    }
	case ID_RPC:
	    {
		struct rt_rpc_internal *rpc =
		    (struct rt_rpc_internal *)ip->idb_ptr;
		RT_RPC_CK_MAGIC(rpc);

		VMOVE(mpt, rpc->rpc_V);
		break;
	    }
	case ID_RHC:
	    {
		struct rt_rhc_internal *rhc =
		    (struct rt_rhc_internal *)ip->idb_ptr;
		RT_RHC_CK_MAGIC(rhc);

		VMOVE(mpt, rhc->rhc_V);
		break;
	    }
	case ID_EPA:
	    {
		struct rt_epa_internal *epa =
		    (struct rt_epa_internal *)ip->idb_ptr;
		RT_EPA_CK_MAGIC(epa);

		VMOVE(mpt, epa->epa_V);
		break;
	    }
	case ID_EHY:
	    {
		struct rt_ehy_internal *ehy =
		    (struct rt_ehy_internal *)ip->idb_ptr;
		RT_EHY_CK_MAGIC(ehy);

		VMOVE(mpt, ehy->ehy_V);
		break;
	    }
	case ID_HYP:
	    {
		struct rt_hyp_internal *hyp =
		    (struct rt_hyp_internal *)ip->idb_ptr;
		RT_HYP_CK_MAGIC(hyp);

		VMOVE(mpt, hyp->hyp_Vi);
		break;
	    }
	case ID_ETO:
	    {
		struct rt_eto_internal *eto =
		    (struct rt_eto_internal *)ip->idb_ptr;
		RT_ETO_CK_MAGIC(eto);

		VMOVE(mpt, eto->eto_V);
		break;
	    }
	case ID_POLY:
	    {
		struct rt_pg_face_internal *_poly;
		struct rt_pg_internal *pg =
		    (struct rt_pg_internal *)ip->idb_ptr;
		RT_PG_CK_MAGIC(pg);

		_poly = pg->poly;
		VMOVE(mpt, _poly->verts);
		break;
	    }
	case ID_SKETCH:
	    {
		struct rt_sketch_internal *skt =
		    (struct rt_sketch_internal *)ip->idb_ptr;
		RT_SKETCH_CK_MAGIC(skt);

		VMOVE(mpt, skt->V);
		break;
	    }
	case ID_EXTRUDE:
	    {
		struct rt_extrude_internal *extr =
		    (struct rt_extrude_internal *)ip->idb_ptr;
		RT_EXTRUDE_CK_MAGIC(extr);

		if (extr->skt && extr->skt->verts) {
		    VJOIN2(mpt, extr->V, extr->skt->verts[0][0], extr->u_vec,
			   extr->skt->verts[0][1], extr->v_vec);
		} else {
		    VMOVE(mpt, extr->V);
		}
		break;
	    }
	case ID_NMG:
	    {
		struct vertex *v;
		struct vertexuse *vu;
		struct edgeuse *eu;
		struct loopuse *lu;
		struct faceuse *fu;
		struct shell *s;
		struct nmgregion *r;
		struct model *m =
		    (struct model *) ip->idb_ptr;
		NMG_CK_MODEL(m);

		/* set default first */
		VSETALL(mpt, 0.0);

		if (BU_LIST_IS_EMPTY(&m->r_hd))
		    break;

		r = BU_LIST_FIRST(nmgregion, &m->r_hd);
		if (!r)
		    break;
		NMG_CK_REGION(r);

		if (BU_LIST_IS_EMPTY(&r->s_hd))
		    break;

		s = BU_LIST_FIRST(shell, &r->s_hd);
		if (!s)
		    break;
		NMG_CK_SHELL(s);

		if (BU_LIST_IS_EMPTY(&s->fu_hd))
		    fu = (struct faceuse *)NULL;
		else
		    fu = BU_LIST_FIRST(faceuse, &s->fu_hd);
		if (fu) {
		    NMG_CK_FACEUSE(fu);
		    lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
		    NMG_CK_LOOPUSE(lu);
		    if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) {
			eu = BU_LIST_FIRST(edgeuse, &lu->down_hd);
			NMG_CK_EDGEUSE(eu);
			NMG_CK_VERTEXUSE(eu->vu_p);
			v = eu->vu_p->v_p;
		    } else {
			vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
			NMG_CK_VERTEXUSE(vu);
			v = vu->v_p;
		    }
		    NMG_CK_VERTEX(v);
		    if (!v->vg_p)
			break;
		    VMOVE(mpt, v->vg_p->coord);
		    break;
		}
		if (BU_LIST_IS_EMPTY(&s->lu_hd))
		    lu = (struct loopuse *)NULL;
		else
		    lu = BU_LIST_FIRST(loopuse, &s->lu_hd);
		if (lu) {
		    NMG_CK_LOOPUSE(lu);
		    if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) {
			eu = BU_LIST_FIRST(edgeuse, &lu->down_hd);
			NMG_CK_EDGEUSE(eu);
			NMG_CK_VERTEXUSE(eu->vu_p);
			v = eu->vu_p->v_p;
		    } else {
			vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
			NMG_CK_VERTEXUSE(vu);
			v = vu->v_p;
		    }
		    NMG_CK_VERTEX(v);
		    if (!v->vg_p)
			break;
		    VMOVE(mpt, v->vg_p->coord);
		    break;
		}
		if (BU_LIST_IS_EMPTY(&s->eu_hd))
		    eu = (struct edgeuse *)NULL;
		else
		    eu = BU_LIST_FIRST(edgeuse, &s->eu_hd);
		if (eu) {
		    NMG_CK_EDGEUSE(eu);
		    NMG_CK_VERTEXUSE(eu->vu_p);
		    v = eu->vu_p->v_p;
		    NMG_CK_VERTEX(v);
		    if (!v->vg_p)
			break;
		    VMOVE(mpt, v->vg_p->coord);
		    break;
		}
		vu = s->vu_p;
		if (vu) {
		    NMG_CK_VERTEXUSE(vu);
		    v = vu->v_p;
		    NMG_CK_VERTEX(v);
		    if (!v->vg_p)
			break;
		    VMOVE(mpt, v->vg_p->coord);
		    break;
		}
	    }
	default:
	    VSETALL(mpt, 0.0);
	    bu_vls_printf(gedp->ged_result_str,
			  "get_solid_keypoint: unrecognized solid type");
	    return GED_ERROR;
    }
    MAT4X3PNT(pt, mat, mpt);
    return GED_OK;
}
Exemple #3
0
int
read_arbn(char *name)
{
    int	npt;			/* # vertex pts to be read in */
    int	npe;			/* # planes from 3 vertex points */
    int	neq;			/* # planes from equation */
    int	nae;			/* # planes from az, el & vertex index */
    int	nface;			/* total number of faces */
    double	*input_points = (double *)0;
    double	*vertex = (double *)0;	/* vertex list of final solid */
    int	last_vertex;		/* index of first unused vertex */
    int	max_vertex;		/* size of vertex array */
    int	*used = (int *)0;	/* plane eqn use count */
    plane_t	*eqn = (plane_t *)0;	/* plane equations */
    int	cur_eq = 0;		/* current (free) equation number */
    int	symm = 0;		/* symmetry about Y used */
    register int	i;
    int	j;
    int	k;
    register int	m;
    point_t	cent;			/* centroid of arbn */
    struct bn_tol	tol;

    /* XXX The tolerance here is sheer guesswork */
    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;

    npt = getint( scard, 10+0*10, 10 );
    npe = getint( scard, 10+1*10, 10 );
    neq = getint( scard, 10+2*10, 10 );
    nae = getint( scard, 10+3*10, 10 );

    nface = npe + neq + nae;
    if ( npt < 1 )  {
        /* Having one point is necessary to compute centroid */
        printf("arbn defined without at least one point\n");
bad:
        if (npt>0) eat( (npt+1)/2 );	/* vertex input_points */
        if (npe>0) eat( (npe+5)/6 );	/* vertex pt index numbers */
        if (neq>0) eat( neq );		/* plane eqns? */
        if (nae>0) eat( (nae+1)/2 );	/* az el & vertex index? */
        return(-1);
    }

    /* Allocate storage for plane equations */
    eqn = (plane_t *)bu_malloc(nface*sizeof(plane_t), "eqn");

    /* Allocate storage for per-plane use count */
    used = (int *)bu_malloc(nface*sizeof(int), "used");

    if ( npt >= 1 )  {
        /* Obtain vertex input_points */
        input_points = (double *)bu_malloc(npt*3*sizeof(double), "input_points");

        if ( getxsoldata( input_points, npt*3, sol_work ) < 0 )
            goto bad;
    }

    /* Get planes defined by three points, 6 per card */
    for ( i=0; i<npe; i += 6 )  {
        if ( get_line( scard, sizeof(scard), "arbn vertex point indices" ) == EOF )  {
            printf("too few cards for arbn %d\n",
                   sol_work);
            return(-1);
        }
        for ( j=0; j<6; j++ )  {
            int	q, r, s;
            point_t	a, b, c;

            q = getint( scard, 10+j*10+0, 4 );
            r = getint( scard, 10+j*10+4, 3 );
            s = getint( scard, 10+j*10+7, 3 );

            if ( q == 0 || r == 0 || s == 0 ) continue;

            if ( q < 0 )  {
                VMOVE( a, &input_points[((-q)-1)*3] );
                a[Y] = -a[Y];
                symm = 1;
            } else {
                VMOVE( a, &input_points[((q)-1)*3] );
            }

            if ( r < 0 )  {
                VMOVE( b, &input_points[((-r)-1)*3] );
                b[Y] = -b[Y];
                symm = 1;
            } else {
                VMOVE( b, &input_points[((r)-1)*3] );
            }

            if ( s < 0 )  {
                VMOVE( c, &input_points[((-s)-1)*3] );
                c[Y] = -c[Y];
                symm = 1;
            } else {
                VMOVE( c, &input_points[((s)-1)*3] );
            }
            if ( bn_mk_plane_3pts( eqn[cur_eq], a, b, c, &tol ) < 0 )  {
                printf("arbn degenerate plane\n");
                VPRINT("a", a);
                VPRINT("b", b);
                VPRINT("c", c);
                continue;
            }
            cur_eq++;
        }
    }

    /* Get planes defined by their equation */
    for ( i=0; i < neq; i++ )  {
        register double	scale;
        if ( get_line( scard, sizeof(scard), "arbn plane equation card" ) == EOF )  {
            printf("too few cards for arbn %d\n",
                   sol_work);
            return(-1);
        }
        eqn[cur_eq][0] = getdouble( scard, 10+0*10, 10 );
        eqn[cur_eq][1] = getdouble( scard, 10+1*10, 10 );
        eqn[cur_eq][2] = getdouble( scard, 10+2*10, 10 );
        eqn[cur_eq][3] = getdouble( scard, 10+3*10, 10 );
        scale = MAGNITUDE(eqn[cur_eq]);
        if ( scale < SMALL )  {
            printf("arbn plane normal too small\n");
            continue;
        }
        scale = 1/scale;
        VSCALE( eqn[cur_eq], eqn[cur_eq], scale );
        eqn[cur_eq][3] *= scale;
        cur_eq++;
    }

    /* Get planes defined by azimuth, elevation, and pt, 2 per card */
    for ( i=0; i < nae;  i += 2 )  {
        if ( get_line( scard, sizeof(scard), "arbn az/el card" ) == EOF )  {
            printf("too few cards for arbn %d\n",
                   sol_work);
            return(-1);
        }
        for ( j=0; j<2; j++ )  {
            double	az, el;
            int	vert_no;
            double	cos_el;
            point_t	pt;

            az = getdouble( scard, 10+j*30+0*10, 10 ) * bn_degtorad;
            el = getdouble( scard, 10+j*30+1*10, 10 ) * bn_degtorad;
            vert_no = getint( scard, 10+j*30+2*10, 10 );
            if ( vert_no == 0 )  break;
            cos_el = cos(el);
            eqn[cur_eq][X] = cos(az)*cos_el;
            eqn[cur_eq][Y] = sin(az)*cos_el;
            eqn[cur_eq][Z] = sin(el);

            if ( vert_no < 0 )  {
                VMOVE( pt, &input_points[((-vert_no)-1)*3] );
                pt[Y] = -pt[Y];
            } else {
                VMOVE( pt, &input_points[((vert_no)-1)*3] );
            }
            eqn[cur_eq][3] = VDOT(pt, eqn[cur_eq]);
            cur_eq++;
        }
    }
    if ( nface != cur_eq )  {
        printf("arbn expected %d faces, got %d\n", nface, cur_eq);
        return(-1);
    }

    /* Average all given points together to find centroid */
    /* This is why there must be at least one (two?) point given */
    VSETALL(cent, 0);
    for ( i=0; i<npt; i++ )  {
        VADD2( cent, cent, &input_points[i*3] );
    }
    VSCALE( cent, cent, 1.0/npt );
    if ( symm )  cent[Y] = 0;

    /* Point normals away from centroid */
    for ( i=0; i<nface; i++ )  {
        double	dist;

        dist = VDOT( eqn[i], cent ) - eqn[i][3];
        /* If dist is negative, 'cent' is inside halfspace */
#define DIST_TOL	(1.0e-8)
#define DIST_TOL_SQ	(1.0e-10)
        if ( dist < -DIST_TOL )  continue;
        if ( dist > DIST_TOL )  {
            /* Flip halfspace over */
            VREVERSE( eqn[i], eqn[i] );
            eqn[i][3] = -eqn[i][3];
        } else {
            /* Centroid lies on this face */
            printf("arbn centroid lies on face\n");
            return(-1);
        }

    }

    /* Release storage for input points */
    bu_free( (char *)input_points, "input_points" );
    input_points = (double *)0;


    /*
     *  ARBN must be convex.  Test for concavity.
     *  Byproduct is an enumeration of all the verticies.
     */
    last_vertex = max_vertex = 0;

    /* Zero face use counts */
    for ( i=0; i<nface; i++ )  {
        used[i] = 0;
    }
    for ( i=0; i<nface-2; i++ )  {
        for ( j=i+1; j<nface-1; j++ )  {
            double	dot;
            int	point_count;	/* # points on this line */

            /* If normals are parallel, no intersection */
            dot = VDOT( eqn[i], eqn[j] );
            if ( !NEAR_ZERO( dot, 0.999999 ) )  continue;

            point_count = 0;
            for ( k=j+1; k<nface; k++ )  {
                point_t	pt;

                if ( bn_mkpoint_3planes( pt, eqn[i], eqn[j], eqn[k] ) < 0 )  continue;

                /* See if point is outside arb */
                for ( m=0; m<nface; m++ )  {
                    if ( i==m || j==m || k==m )  continue;
                    if ( VDOT(pt, eqn[m])-eqn[m][3] > DIST_TOL )
                        goto next_k;
                }
                /* See if vertex already was found */
                for ( m=0; m<last_vertex; m++ )  {
                    vect_t	dist;
                    VSUB2( dist, pt, &vertex[m*3] );
                    if ( MAGSQ(dist) < DIST_TOL_SQ )
                        goto next_k;
                }

                /*
                 *  Add point to vertex array.
                 *  If more room needed, realloc.
                 */
                if ( last_vertex >= max_vertex )  {
                    if ( max_vertex == 0 )   {
                        max_vertex = 3;
                        vertex = (double *)bu_malloc( max_vertex*3*sizeof(double), "vertex" );
                    } else {
                        max_vertex *= 10;
                        vertex = (double *)bu_realloc( (char *)vertex, max_vertex*3*sizeof(double), "vertex" );
                    }
                }

                VMOVE( &vertex[last_vertex*3], pt );
                last_vertex++;
                point_count++;

                /* Increment "face used" counts */
                used[i]++;
                used[j]++;
                used[k]++;
next_k:
                ;
            }
            if ( point_count > 2 )  {
                printf("arbn: warning, point_count on line=%d\n", point_count);
            }
        }
    }

    /* If any planes were not used, then arbn is not convex */
    for ( i=0; i<nface; i++ )  {
        if ( used[i] != 0 )  continue;	/* face was used */
        printf("arbn face %d unused, solid is not convex\n", i);
        return(-1);
    }

    /* Write out the solid ! */
    i = mk_arbn( outfp, name, nface, eqn );

    if ( input_points )  bu_free( (char *)input_points, "input_points" );
    if ( vertex )  bu_free( (char *)vertex, "vertex" );
    if ( eqn )  bu_free( (char *)eqn, "eqn" );
    if ( used )  bu_free( (char *)used, "used" );

    return(i);
}
Exemple #4
0
/**
 * "Tessellate" an ARB into an NMG data structure.
 * Purely a mechanical transformation of one faceted object
 * into another.
 *
 * Returns -
 * -1 failure
 *  0 OK.  *r points to nmgregion that holds this tessellation.
 */
int
rt_arbn_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *tol)
{
    struct rt_arbn_internal *aip;
    struct shell *s;
    struct faceuse **fu;		/* array of faceuses */
    size_t nverts;		/* maximum possible number of vertices = neqn!/(3!(neqn-3)! */
    size_t point_count = 0;	/* actual number of vertices */
    size_t face_count = 0;	/* actual number of faces built */
    size_t i, j, k, l, n;
    struct arbn_pts *pts;
    struct arbn_edges *edges;		/* A list of edges for each plane eqn (each face) */
    size_t *edge_count;	/* number of edges for each face */
    size_t max_edge_count; /* maximum number of edges for any face */
    struct vertex **verts;	/* Array of pointers to vertex structs */
    struct vertex ***loop_verts;	/* Array of pointers to vertex structs to pass to nmg_cmface */

    RT_CK_DB_INTERNAL(ip);
    aip = (struct rt_arbn_internal *)ip->idb_ptr;
    RT_ARBN_CK_MAGIC(aip);

    /* Allocate memory for the vertices */
    nverts = aip->neqn * (aip->neqn-1) * (aip->neqn-2) / 6;
    pts = (struct arbn_pts *)bu_calloc(nverts, sizeof(struct arbn_pts), "rt_arbn_tess: pts");

    /* Allocate memory for arbn_edges */
    edges = (struct arbn_edges *)bu_calloc(aip->neqn*aip->neqn, sizeof(struct arbn_edges) ,
					   "rt_arbn_tess: edges");
    edge_count = (size_t *)bu_calloc(aip->neqn, sizeof(size_t), "rt_arbn_tess: edge_count");

    /* Allocate memory for faceuses */
    fu = (struct faceuse **)bu_calloc(aip->neqn, sizeof(struct faceuse *), "rt_arbn_tess: fu");

    /* Calculate all vertices */
    for (i = 0; i < aip->neqn; i++) {
	for (j = i + 1; j < aip->neqn; j++) {
	    for (k = j + 1; k < aip->neqn; k++) {
		int keep_point = 1;

		if (bn_mkpoint_3planes(pts[point_count].pt, aip->eqn[i], aip->eqn[j], aip->eqn[k]))
		    continue;

		for (l = 0; l < aip->neqn; l++) {
		    if (l == i || l == j || l == k)
			continue;
		    if (DIST_PT_PLANE(pts[point_count].pt, aip->eqn[l]) > tol->dist) {
			keep_point = 0;
			break;
		    }
		}
		if (keep_point) {
		    pts[point_count].plane_no[0] = i;
		    pts[point_count].plane_no[1] = j;
		    pts[point_count].plane_no[2] = k;
		    point_count++;
		}
	    }
	}
    }

    /* Allocate memory for the NMG vertex pointers */
    verts = (struct vertex **)bu_calloc(point_count, sizeof(struct vertex *) ,
					"rt_arbn_tess: verts");

    /* Associate points with vertices */
    for (i = 0; i < point_count; i++)
	pts[i].vp = &verts[i];

    /* Check for duplicate points */
    for (i = 0; i < point_count; i++) {
	for (j = i + 1; j < point_count; j++) {
	    if (DIST_PT_PT_SQ(pts[i].pt, pts[j].pt) < tol->dist_sq) {
		/* These two points should point to the same vertex */
		pts[j].vp = pts[i].vp;
	    }
	}
    }

    /* Make list of edges for each face */
    for (i = 0; i < aip->neqn; i++) {
	/* look for a point that lies in this face */
	for (j = 0; j < point_count; j++) {
	    if (pts[j].plane_no[0] != (int)i
		&& pts[j].plane_no[1] != (int)i
		&& pts[j].plane_no[2] != (int)i)
		continue;

	    /* look for another point that shares plane "i" and another with this one */
	    for (k = j + 1; k < point_count; k++) {
		size_t match = (size_t)-1;
		size_t pt1, pt2;
		int duplicate = 0;

		/* skip points not on plane "i" */
		if (pts[k].plane_no[0] != (int)i
		    && pts[k].plane_no[1] != (int)i
		    && pts[k].plane_no[2] != (int)i)
		    continue;

		for (l = 0; l < 3; l++) {
		    for (n = 0; n < 3; n++) {
			if (pts[j].plane_no[l] == pts[k].plane_no[n]
			    && pts[j].plane_no[l] != (int)i) {
			    match = pts[j].plane_no[l];
			    break;
			}
		    }
		    if (match != (size_t)-1)
			break;
		}

		if (match == (size_t)-1)
		    continue;

		/* convert equivalent points to lowest point number */
		pt1 = j;
		pt2 = k;
		for (l = 0; l < pt1; l++) {
		    if (pts[pt1].vp == pts[l].vp) {
			pt1 = l;
			break;
		    }
		}
		for (l = 0; l < pt2; l++) {
		    if (pts[pt2].vp == pts[l].vp) {
			pt2 = l;
			break;
		    }
		}

		/* skip null edges */
		if (pt1 == pt2)
		    continue;

		/* check for duplicate edge */
		for (l = 0; l < edge_count[i]; l++) {
		    if ((edges[LOC(i, l)].v1_no == (int)pt1
			 && edges[LOC(i, l)].v2_no == (int)pt2)
			|| (edges[LOC(i, l)].v2_no == (int)pt1
			    && edges[LOC(i, l)].v1_no == (int)pt2))
		    {
			duplicate = 1;
			break;
		    }
		}
		if (duplicate)
		    continue;

		/* found an edge belonging to faces "i" and "match" */
		if (edge_count[i] == aip->neqn) {
		    bu_log("Too many edges found for one face\n");
		    goto fail;
		}
		edges[LOC(i, edge_count[i])].v1_no = pt1;
		edges[LOC(i, edge_count[i])].v2_no = pt2;
		edge_count[i]++;
	    }
	}
    }

    /* for each face, sort the list of edges into a loop */
    Sort_edges(edges, edge_count, aip);

    /* Get max number of edges for any face */
    max_edge_count = 0;
    for (i = 0; i < aip->neqn; i++)
	if (edge_count[i] > max_edge_count)
	    max_edge_count = edge_count[i];

    /* Allocate memory for array to pass to nmg_cmface */
    loop_verts = (struct vertex ***) bu_calloc(max_edge_count, sizeof(struct vertex **) ,
					       "rt_arbn_tess: loop_verts");

    *r = nmg_mrsv(m);	/* Make region, empty shell, vertex */
    s = BU_LIST_FIRST(shell, &(*r)->s_hd);

    /* Make the faces */
    for (i = 0; i < aip->neqn; i++) {
	int loop_length = 0;

	for (j = 0; j < edge_count[i]; j++) {
	    /* skip zero length edges */
	    if (pts[edges[LOC(i, j)].v1_no].vp == pts[edges[LOC(i, j)].v2_no].vp)
		continue;

	    /* put vertex pointers into loop_verts array */
	    loop_verts[loop_length] = pts[edges[LOC(i, j)].v2_no].vp;
	    loop_length++;
	}

	/* Make the face if there is are least 3 vertices */
	if (loop_length > 2)
	    fu[face_count++] = nmg_cmface(s, loop_verts, loop_length);
    }

    /* Associate vertex geometry */
    for (i = 0; i < point_count; i++) {
	if (!(*pts[i].vp))
	    continue;

	if ((*pts[i].vp)->vg_p)
	    continue;

	nmg_vertex_gv(*pts[i].vp, pts[i].pt);
    }

    bu_free((char *)pts, "rt_arbn_tess: pts");
    bu_free((char *)edges, "rt_arbn_tess: edges");
    bu_free((char *)edge_count, "rt_arbn_tess: edge_count");
    bu_free((char *)verts, "rt_arbn_tess: verts");
    bu_free((char *)loop_verts, "rt_arbn_tess: loop_verts");

    /* Associate face geometry */
    for (i = 0; i < face_count; i++) {
	if (nmg_fu_planeeqn(fu[i], tol)) {
	    bu_log("Failed to calculate face plane equation\n");
	    bu_free((char *)fu, "rt_arbn_tess: fu");
	    nmg_kr(*r);
	    *r = (struct nmgregion *)NULL;
	    return -1;
	}
    }

    bu_free((char *)fu, "rt_arbn_tess: fu");

    nmg_fix_normals(s, tol);

    (void)nmg_mark_edges_real(&s->l.magic);

    /* Compute "geometry" for region and shell */
    nmg_region_a(*r, tol);

    return 0;

fail:
    bu_free((char *)pts, "rt_arbn_tess: pts");
    bu_free((char *)edges, "rt_arbn_tess: edges");
    bu_free((char *)edge_count, "rt_arbn_tess: edge_count");
    bu_free((char *)verts, "rt_arbn_tess: verts");
    return -1;
}
Exemple #5
0
/**
 * Brute force through all possible plane intersections.
 * Generate all edge lines, then intersect the line with all
 * the other faces to find the vertices on that line.
 * If the geometry is correct, there will be no more than two.
 * While not the fastest strategy, this will produce an accurate
 * plot without requiring extra bookkeeping.
 * Note that the vectors will be drawn in no special order.
 */
int
rt_arbn_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *tol, const struct rt_view_info *UNUSED(info))
{
    struct rt_arbn_internal *aip;
    size_t i;
    size_t j;
    size_t k;

    BU_CK_LIST_HEAD(vhead);
    RT_CK_DB_INTERNAL(ip);
    aip = (struct rt_arbn_internal *)ip->idb_ptr;
    RT_ARBN_CK_MAGIC(aip);

    for (i = 0; i < aip->neqn - 1; i++) {
	for (j = i + 1; j < aip->neqn; j++) {
	    double dot;
	    int point_count;	/* # points on this line */
	    point_t a, b;		/* start and end points */
	    vect_t dist;

	    VSETALL(a, 0);
	    VSETALL(b, 0);

	    /* 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 all other planes */
	    point_count = 0;
	    for (k = 0; k < aip->neqn; k++) {
		size_t m;
		point_t pt;
		size_t next_k;

		next_k = 0;

		if (k == i || k == j) continue;
		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;

		if (point_count <= 0) {
		    RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_MOVE);
		    VMOVE(a, pt);
		} else if (point_count == 1) {
		    VSUB2(dist, pt, a);
		    if (MAGSQ(dist) < tol->dist_sq) continue;
		    RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_DRAW);
		    VMOVE(b, pt);
		} else {
		    VSUB2(dist, pt, a);
		    if (MAGSQ(dist) < tol->dist_sq) continue;
		    VSUB2(dist, pt, b);
		    if (MAGSQ(dist) < tol->dist_sq) continue;
		    bu_log("rt_arbn_plot() error, point_count=%d (>2) on edge %zu/%zu, non-convex\n",
			   point_count+1,
			   i, j);
		    VPRINT(" a", a);
		    VPRINT(" b", b);
		    VPRINT("pt", pt);
		    RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_DRAW);	/* draw it */
		}
		point_count++;
	    }
	    /* Point counts of 1 are (generally) not harmful,
	     * occurring on pyramid peaks and the like.
	     */
	}
    }
    return 0;
}
Exemple #6
0
/**
 * 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 */
}