示例#1
0
/*
 * M A K E _ N T S C _ X Y Z 2 R G B
 *
 * Create the map from
 * CIE XYZ perceptual space into
 * an idealized RGB space assuming NTSC primaries with D6500 white.
 * Only high-quality television-studio monitors are like this, but...
 */
void
make_ntsc_xyz2rgb(fastf_t *xyz2rgb)
{
    mat_t rgb2xyz;
    point_t tst, newpt;

    if (rt_clr__cspace_to_xyz(rgb_NTSC, rgb2xyz) == 0)
	bu_exit(EXIT_FAILURE, "make_ntsc_xyz2rgb() can't initialize color space\n");
    bn_mat_inv(xyz2rgb, rgb2xyz);

#if 1
    /* Verify that it really works, I'm a skeptic */
    VSET(tst, 1, 1, 1);
    MAT3X3VEC(newpt, rgb2xyz, tst);
    VPRINT("white_rgb (i)", tst);
    VPRINT("white_xyz (o)", newpt);

    VSET(tst, 0.313,     0.329,      0.358);
    MAT3X3VEC(newpt, xyz2rgb, tst);
    VPRINT("white_xyz (i)", tst);
    VPRINT("white_rgb (o)", newpt);

    VSET(tst, 1, 0, 0);
    MAT3X3VEC(newpt, rgb2xyz, tst);
    VPRINT("red_rgb (i)", tst);
    VPRINT("red_xyz (o)", newpt);

    VSET(tst, 0.670,     0.330,      0.000);
    MAT3X3VEC(newpt, xyz2rgb, tst);
    VPRINT("red_xyz (i)", tst);
    VPRINT("red_rgb (o)", newpt);

    VSET(tst, 0, 1, 0);
    MAT3X3VEC(newpt, rgb2xyz, tst);
    VPRINT("grn_rgb (i)", tst);
    VPRINT("grn_xyz (o)", newpt);

    VSET(tst, 0.210,     0.710,      0.080);
    MAT3X3VEC(newpt, xyz2rgb, tst);
    VPRINT("grn_xyz (i)", tst);
    VPRINT("grn_rgb (o)", newpt);

    VSET(tst, 0, 0, 1);
    MAT3X3VEC(newpt, rgb2xyz, tst);
    VPRINT("blu_rgb (i)", tst);
    VPRINT("blu_xyz (o)", newpt);

    VSET(tst, 0.140,     0.080,      0.780);
    MAT3X3VEC(newpt, xyz2rgb, tst);
    VPRINT("blu_xyz (i)", tst);
    VPRINT("blu_rgb (o)", newpt);
#endif
}
示例#2
0
int
main(int ac, char **av)
{
    unsigned char rgb[4];
    float src[3];
    point_t dest;
    point_t xyz;
    size_t ret;

    if (ac > 1)
	bu_log("Usage: %s\n", av[0]);

    spectrum = bn_table_make_uniform(nsamp, min_nm, max_nm);
    BN_GET_TABDATA(curve, spectrum);

    rt_spect_make_CIE_XYZ(&cie_x, &cie_y, &cie_z, spectrum);
    make_ntsc_xyz2rgb(xyz2rgb);

    for (;;) {
	if (fread(rgb, 1, 3, stdin) != 3) break;
	if (feof(stdin)) break;

	VSET(src, rgb[0]/255., rgb[1]/255., rgb[2]/255.);

	rt_spect_reflectance_rgb(curve, src);

	spect_curve_to_xyz(xyz, curve, cie_x, cie_y, cie_z);

	MAT3X3VEC(dest, xyz2rgb, xyz);

	if (dest[0] > 1 || dest[1] > 1 || dest[2] > 1 ||
	    dest[0] < 0 || dest[1] < 0 || dest[2] < 0) {
	    VPRINT("src ", src);
	    VPRINT("dest", dest);
	}

	if (dest[0] > 1) dest[0] = 1;
	if (dest[1] > 1) dest[1] = 1;
	if (dest[2] > 1) dest[2] = 1;
	if (dest[0] < 0) dest[0] = 0;
	if (dest[1] < 0) dest[1] = 0;
	if (dest[2] < 0) dest[2] = 0;

	VSCALE(rgb, dest, 255.0);

	ret = fwrite(rgb, 1, 3, stdout);
	if (ret != 3)
	    perror("fwrite");
    }

    return 0;
}
示例#3
0
int
main(int argc, char **argv)
{
    void anim_dir2mat(fastf_t *, const fastf_t *, const fastf_t *), anim_y_p_r2mat(fastf_t *, double, double, double), anim_add_trans(fastf_t *, const fastf_t *, const fastf_t *), anim_mat_print(FILE *, const fastf_t *, int);
    int get_args(int argc, char **argv), track_prep(void), val, frame, go, i, count;
    fastf_t y_rot, distance, yaw, pitch, roll;
    vect_t p1, p2, p3, dir, dir2, wheel_now, wheel_prev;
    vect_t zero, position, vdelta, temp, to_track, to_front;
    mat_t mat_v, wmat, mat_x;
    FILE *stream;
    int last_frame;

    VSETALL(zero, 0.0);
    VSETALL(to_track, 0.0);
    VSETALL(centroid, 0.0);
    VSETALL(rcentroid, 0.0);
    init_dist = y_rot = radius= 0.0;
    first_frame = num_wheels = steer = axes = cent = links_placed=0;
    num_wheels = num_links = last_frame = 0;
    MAT_IDN(mat_v);
    MAT_IDN(mat_x);
    MAT_IDN(wmat);
    MAT_IDN(m_axes);
    MAT_IDN(m_rev_axes);

    if (!get_args(argc, argv)) {
	fprintf(stderr, "anim_hardtrack: argument error.");
	return(-1);
    }

    if (axes || cent ) {
	/* vehicle has own reference frame */
	anim_add_trans(m_axes, centroid, zero);
	anim_add_trans(m_rev_axes, zero, rcentroid);
    }

    /* get track information from specified file */

    if (!(stream = fopen(*(argv+bu_optind), "rb"))) {
	fprintf(stderr, "Anim_hardtrack: Could not open file %s.\n", *(argv+bu_optind));
	return(0);
    }
    num_wheels = -1;
    if (radius) {
	while (!feof(stream)) {
	    fscanf(stream, "%*f %*f %*f");
	    num_wheels++;
	}
    } else {
	while (!feof(stream)) {
	    fscanf(stream, "%*f %*f %*f %*f");
	    num_wheels++;
	}
    }
    rewind(stream);

    /*allocate memory for track information*/
    x = (struct all *) bu_calloc(num_wheels, sizeof(struct all), "struct all");
    /*read rest of track info */
    for (i=0;i<NW;i++) {
	fscanf(stream, "%lf %lf %lf", temp, temp+1, temp+2);
	if (radius)
	    x[i].w.rad = radius;
	else
	    fscanf(stream, "%lf", & x[i].w.rad);
	MAT4X3PNT(x[i].w.pos, m_rev_axes, temp);
	if (i==0)
	    track_y = x[0].w.pos[1];
	else
	    x[i].w.pos[1] = track_y;
    }
    (void) fclose(stream);

    (void) track_prep();

    if (get_circumf) {
	printf("%.10g\n", tracklen);
	return(0);
    }

    /* initialize to_track */
    VSET(to_track, 0.0, track_y, 0.0);
    VSET(to_front, 1.0, 0.0, 0.0);

    if ((!print_link)&&(!print_wheel)) {
	fprintf(stderr, "anim_hardtrack: no ouput requested. Use -l or -w.\n");
	bu_exit(0, NULL);
    }
    /* main loop */
    distance = 0.0;
    if (!steer)
	frame = first_frame;
    else
	frame = first_frame-1;
    for (val = 3; val > 2; frame++) {
	go = 1;
	/*p2 is current position. p3 is next;p1 is previous*/
	VMOVE(p1, p2);
	VMOVE(p2, p3);
	scanf("%*f");/*time stamp*/
	val = scanf("%lf %lf %lf", p3, p3+1, p3 + 2);
	if (!steer) {
	    scanf("%lf %lf %lf", &yaw, &pitch, &roll);
	    anim_dy_p_r2mat(mat_v, yaw, pitch, roll);
	    anim_add_trans(mat_v, p3, rcentroid);
	}
	else {
	    /* analyze positions for steering */
	    /*get useful direction unit vectors*/
	    if (frame == first_frame) {
		/* first frame*/
		VSUBUNIT(dir, p3, p2);
		VMOVE(dir2, dir);
	    }
	    else if (val < 3) {
		/*last frame*/
		VSUBUNIT(dir, p2, p1);
		VMOVE(dir2, dir);
	    }
	    else if (frame > first_frame) {
		/*normal*/
		VSUBUNIT(dir, p3, p1);
		VSUBUNIT(dir2, p2, p1);/*needed for vertical case*/
	    }
	    else go = 0;/*first time through loop;no p2*/

			/*create matrix which would move vehicle*/
	    anim_dir2mat(mat_v, dir, dir2);
	    anim_add_trans(mat_v, p2, rcentroid);
	}

	/*determine distance traveled*/
	VMOVE(wheel_prev, wheel_now);
	MAT4X3PNT(wheel_now, mat_v, to_track);
	if (frame > first_frame) {
	    /* increment distance by distance moved */
	    VSUB2(vdelta, wheel_now, wheel_prev);
	    MAT3X3VEC(temp, mat_v, to_front);/*new front of vehicle*/
	    distance += VDOT(temp, vdelta);/*portion of vdelta in line with track*/
	}

	if (go) {
	    if (print_mode==TRACK_ANIM) {
		printf("start %d;\nclean;\n", frame);
	    } else if (print_mode==TRACK_ARCED) {
		if (frame != arced_frame) continue;
		last_frame = 1;
	    }
	    if (print_link) {
		for (count=0;count<num_links;count++) {
		    (void) get_link(position, &y_rot, distance+tracklen*count/num_links+init_dist);
		    anim_y_p_r2mat(wmat, 0.0, y_rot+r[count].ang, 0.0);
		    anim_add_trans(wmat, position, r[count].pos);
		    if ((axes || cent) && links_placed) {
			/* link moved from vehicle coords */
			bn_mat_mul(mat_x, wmat, m_rev_axes);
			bn_mat_mul(wmat, m_axes, mat_x);
		    }
		    else if (axes || cent) {
			/* link moved to vehicle coords */
			MAT_MOVE(mat_x, wmat);
			bn_mat_mul(wmat, m_axes, mat_x);
		    }
		    if (print_mode==TRACK_ANIM) {
			printf("anim %s.%d matrix %s\n", *(argv+link_nindex), count, link_cmd);
			anim_mat_printf(stdout, wmat, "%.10g ", "\n", ";\n");
		    } else if (print_mode==TRACK_ARCED) {
			printf("arced %s.%d matrix %s ", *(argv+link_nindex), count, link_cmd);
			anim_mat_printf(stdout, wmat, "%.10g ", "", "\n");
		    }
		}
	    }
	    if (print_wheel) {
		for (count = 0;count<num_wheels;count++) {
		    anim_y_p_r2mat(wmat, 0.0, -distance/x[count].w.rad, 0.0);
		    VREVERSE(temp, x[count].w.pos);
		    anim_add_trans(wmat, x[count].w.pos, temp);
		    if (axes || cent) {
			bn_mat_mul(mat_x, wmat, m_rev_axes);
			bn_mat_mul(wmat, m_axes, mat_x);
		    }
		    if (print_mode==TRACK_ANIM) {
			printf("anim %s.%d matrix %s\n", *(argv+wheel_nindex), count, wheel_cmd);
			anim_mat_printf(stdout, wmat, "%.10g ", "\n", ";\n");
		    } else if (print_mode==TRACK_ARCED) {
			printf("arced %s.%d matrix %s ", *(argv+wheel_nindex), count, wheel_cmd);
			anim_mat_printf(stdout, wmat, "%.10g ", "", "\n");
		    }
		}
	    }
	    if (print_mode==TRACK_ANIM)
		printf("end;\n");
	}
	if (last_frame) break;
    }

    if (x) {
	bu_free(x, "struct all");
    }
    if (r) {
	bu_free(r, "struct rlink");
    }
    return( 0 );
}
示例#4
0
文件: superell.c 项目: kanzure/brlcad
/**
 * Calculate a bounding RPP for a superell
 */
int
rt_superell_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *UNUSED(tol)) {

    struct rt_superell_internal *eip;
    fastf_t magsq_a, magsq_b, magsq_c;
    vect_t Au, Bu, Cu;
    mat_t R;
    vect_t w1, w2, P;	/* used for bounding RPP */
    fastf_t f;

    eip = (struct rt_superell_internal *)ip->idb_ptr;
    RT_SUPERELL_CK_MAGIC(eip);

    magsq_a = MAGSQ(eip->a);
    magsq_b = MAGSQ(eip->b);
    magsq_c = MAGSQ(eip->c);


    /* Create unit length versions of A, B, C */
    f = 1.0/sqrt(magsq_a);
    VSCALE(Au, eip->a, f);
    f = 1.0/sqrt(magsq_b);
    VSCALE(Bu, eip->b, f);
    f = 1.0/sqrt(magsq_c);
    VSCALE(Cu, eip->c, f);

    MAT_IDN(R);
    VMOVE(&R[0], Au);
    VMOVE(&R[4], Bu);
    VMOVE(&R[8], Cu);

    /* Compute bounding RPP */
    VSET(w1, magsq_a, magsq_b, magsq_c);

    /* X */
    VSET(P, 1.0, 0, 0);		/* bounding plane normal */
    MAT3X3VEC(w2, R, P);		/* map plane to local coord syst */
    VELMUL(w2, w2, w2);		/* square each term */
    f = VDOT(w1, w2);
    f = sqrt(f);
    (*min)[X] = eip->v[X] - f;	/* V.P +/- f */
    (*max)[X] = eip->v[X] + f;

    /* Y */
    VSET(P, 0, 1.0, 0);		/* bounding plane normal */
    MAT3X3VEC(w2, R, P);		/* map plane to local coord syst */
    VELMUL(w2, w2, w2);		/* square each term */
    f = VDOT(w1, w2);
    f = sqrt(f);
    (*min)[Y] = eip->v[Y] - f;	/* V.P +/- f */
    (*max)[Y] = eip->v[Y] + f;

    /* Z */
    VSET(P, 0, 0, 1.0);		/* bounding plane normal */
    MAT3X3VEC(w2, R, P);		/* map plane to local coord syst */
    VELMUL(w2, w2, w2);		/* square each term */
    f = VDOT(w1, w2);
    f = sqrt(f);
    (*min)[Z] = eip->v[Z] - f;	/* V.P +/- f */
    (*max)[Z] = eip->v[Z] + f;

    return 0;
}
示例#5
0
/**
 * In theory, the grid can be specified by providing any two of
 * these sets of parameters:
 *
 * number of pixels (width, height)
 * viewsize (in model units, mm)
 * number of grid cells (cell_width, cell_height)
 *
 * however, for now, it is required that the view size always be
 * specified, and one or the other parameter be provided.
 */
void
grid_setup(void)
{
    vect_t temp;
    mat_t toEye;

    if (viewsize <= 0.0)
	bu_exit(EXIT_FAILURE, "viewsize <= 0");
    /* model2view takes us to eye_model location & orientation */
    MAT_IDN(toEye);
    MAT_DELTAS_VEC_NEG(toEye, eye_model);
    Viewrotscale[15] = 0.5*viewsize;	/* Viewscale */
    bn_mat_mul(model2view, Viewrotscale, toEye);
    bn_mat_inv(view2model, model2view);

    /* Determine grid cell size and number of pixels */
    if (cell_newsize) {
	if (cell_width <= 0.0) cell_width = cell_height;
	if (cell_height <= 0.0) cell_height = cell_width;
	width = (viewsize / cell_width) + 0.99;
	height = (viewsize / (cell_height*aspect)) + 0.99;
	cell_newsize = 0;
    } else {
	/* Chop -1.0..+1.0 range into parts */
	cell_width = viewsize / width;
	cell_height = viewsize / (height*aspect);
    }

    /*
     * Optional GIFT compatibility, mostly for RTG3.  Round coordinates
     * of lower left corner to fall on integer- valued coordinates, in
     * "gift_grid_rounding" units.
     */
    if (gift_grid_rounding > 0.0) {
	point_t v_ll;		/* view, lower left */
	point_t m_ll;		/* model, lower left */
	point_t hv_ll;		/* hv, lower left*/
	point_t hv_wanted;
	vect_t hv_delta;
	vect_t m_delta;
	mat_t model2hv;
	mat_t hv2model;

	/* Build model2hv matrix, including mm2inches conversion */
	MAT_COPY(model2hv, Viewrotscale);
	model2hv[15] = gift_grid_rounding;
	bn_mat_inv(hv2model, model2hv);

	VSET(v_ll, -1, -1, 0);
	MAT4X3PNT(m_ll, view2model, v_ll);
	MAT4X3PNT(hv_ll, model2hv, m_ll);
	VSET(hv_wanted, floor(hv_ll[X]), floor(hv_ll[Y]), floor(hv_ll[Z]));
	VSUB2(hv_delta, hv_ll, hv_wanted);

	MAT4X3PNT(m_delta, hv2model, hv_delta);
	VSUB2(eye_model, eye_model, m_delta);
	MAT_DELTAS_VEC_NEG(toEye, eye_model);
	bn_mat_mul(model2view, Viewrotscale, toEye);
	bn_mat_inv(view2model, model2view);
    }

    /* Create basis vectors dx and dy for emanation plane (grid) */
    VSET(temp, 1, 0, 0);
    MAT3X3VEC(dx_unit, view2model, temp);	/* rotate only */
    VSCALE(dx_model, dx_unit, cell_width);

    VSET(temp, 0, 1, 0);
    MAT3X3VEC(dy_unit, view2model, temp);	/* rotate only */
    VSCALE(dy_model, dy_unit, cell_height);

    if (stereo) {
	/* Move left 2.5 inches (63.5mm) */
	VSET(temp, -63.5*2.0/viewsize, 0, 0);
	bu_log("red eye: moving %f relative screen (left)\n", temp[X]);
	MAT4X3VEC(left_eye_delta, view2model, temp);
	VPRINT("left_eye_delta", left_eye_delta);
    }

    /* "Lower left" corner of viewing plane */
    if (rt_perspective > 0.0) {
	fastf_t zoomout;
	zoomout = 1.0 / tan(DEG2RAD * rt_perspective / 2.0);
	VSET(temp, -1, -1/aspect, -zoomout);	/* viewing plane */

	/*
	 * divergence is perspective angle divided by the number of
	 * pixels in that angle. Extra factor of 0.5 is because
	 * perspective is a full angle while divergence is the tangent
	 * (slope) of a half angle.
	 */
	APP.a_diverge = tan(DEG2RAD * rt_perspective * 0.5 / width);
	APP.a_rbeam = 0;
    } else {
	/* all rays go this direction */
	VSET(temp, 0, 0, -1);
	MAT4X3VEC(APP.a_ray.r_dir, view2model, temp);
	VUNITIZE(APP.a_ray.r_dir);

	VSET(temp, -1, -1/aspect, 0);	/* eye plane */
	APP.a_rbeam = 0.5 * viewsize / width;
	APP.a_diverge = 0;
    }
    if (ZERO(APP.a_rbeam) && ZERO(APP.a_diverge))
	bu_exit(EXIT_FAILURE, "zero-radius beam");
    MAT4X3PNT(viewbase_model, view2model, temp);

    if (jitter & JITTER_FRAME) {
	/* Move the frame in a smooth circular rotation in the plane */
	fastf_t ang;	/* radians */
	fastf_t dx, dy;

	ang = curframe * frame_delta_t * M_2PI / 10;	/* 10 sec period */
	dx = cos(ang) * 0.5;	/* +/- 1/4 pixel width in amplitude */
	dy = sin(ang) * 0.5;
	VJOIN2(viewbase_model, viewbase_model,
	       dx, dx_model,
	       dy, dy_model);
    }

    if (cell_width <= 0 || cell_width >= INFINITY ||
	cell_height <= 0 || cell_height >= INFINITY) {
	bu_log("grid_setup: cell size ERROR (%g, %g) mm\n",
	       cell_width, cell_height);
	bu_exit(EXIT_FAILURE, "cell size");
    }
    if (width <= 0 || height <= 0) {
	bu_log("grid_setup: ERROR bad image size (%zu, %zu)\n",
	       width, height);
	bu_exit(EXIT_FAILURE, "bad size");
    }
}
示例#6
0
文件: rec.c 项目: cogitokat/brlcad
/**
 * R E C _ B B O X
 *
 * Calculate the RPP for an REC
 */
int
rt_rec_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *UNUSED(tol)) {
    mat_t R;
    vect_t P, w1;
    fastf_t f, tmp, z;
    double magsq_h, magsq_a, magsq_b, magsq_c, magsq_d;
    double mag_h, mag_a, mag_b;
    struct rt_tgc_internal *tip;

    RT_CK_DB_INTERNAL(ip);

    tip = (struct rt_tgc_internal *)ip->idb_ptr;
    RT_TGC_CK_MAGIC(tip);

    mag_h = sqrt(magsq_h = MAGSQ(tip->h));
    mag_a = sqrt(magsq_a = MAGSQ(tip->a));
    mag_b = sqrt(magsq_b = MAGSQ(tip->b));
    magsq_c = MAGSQ(tip->c);
    magsq_d = MAGSQ(tip->d);

    MAT_IDN(R);
    f = 1.0/mag_a;
    VSCALE(&R[0], tip->a, f);
    f = 1.0/mag_b;
    VSCALE(&R[4], tip->b, f);
    f = 1.0/mag_h;
    VSCALE(&R[8], tip->h, f);

    /* X */
    VSET(P, 1.0, 0, 0);		/* bounding plane normal */
    MAT3X3VEC(w1, R, P);		/* map plane into local coord syst */
    /* 1st end ellipse (no Z part) */
    tmp = magsq_a * w1[X] * w1[X] + magsq_b * w1[Y] * w1[Y];
    if (tmp > SMALL)
	f = sqrt(tmp);		/* XY part */
    else
	f = 0;
    (*min)[X] = tip->v[X] - f;	/* V.P +/- f */
    (*max)[X] = tip->v[X] + f;
    /* 2nd end ellipse */
    z = w1[Z] * mag_h;		/* Z part */
    tmp = magsq_c * w1[X] * w1[X] + magsq_d * w1[Y] * w1[Y];
    if (tmp > SMALL)
	f = sqrt(tmp);		/* XY part */
    else
	f = 0;
    if (tip->v[X] - f + z < (*min)[X])
	(*min)[X] = tip->v[X] - f + z;
    if (tip->v[X] + f + z > (*max)[X])
	(*max)[X] = tip->v[X] + f + z;

    /* Y */
    VSET(P, 0, 1.0, 0);		/* bounding plane normal */
    MAT3X3VEC(w1, R, P);		/* map plane into local coord syst */
    /* 1st end ellipse (no Z part) */
    tmp = magsq_a * w1[X] * w1[X] + magsq_b * w1[Y] * w1[Y];
    if (tmp > SMALL)
	f = sqrt(tmp);		/* XY part */
    else
	f = 0;
    (*min)[Y] = tip->v[Y] - f;	/* V.P +/- f */
    (*max)[Y] = tip->v[Y] + f;
    /* 2nd end ellipse */
    z = w1[Z] * mag_h;		/* Z part */
    tmp = magsq_c * w1[X] * w1[X] + magsq_d * w1[Y] * w1[Y];
    if (tmp > SMALL)
	f = sqrt(tmp);		/* XY part */
    else
	f = 0;
    if (tip->v[Y] - f + z < (*min)[Y])
	(*min)[Y] = tip->v[Y] - f + z;
    if (tip->v[Y] + f + z > (*max)[Y])
	(*max)[Y] = tip->v[Y] + f + z;

    /* Z */
    VSET(P, 0, 0, 1.0);		/* bounding plane normal */
    MAT3X3VEC(w1, R, P);		/* map plane into local coord syst */
    /* 1st end ellipse (no Z part) */
    tmp = magsq_a * w1[X] * w1[X] + magsq_b * w1[Y] * w1[Y];
    if (tmp > SMALL)
	f = sqrt(tmp);		/* XY part */
    else
	f = 0;
    (*min)[Z] = tip->v[Z] - f;	/* V.P +/- f */
    (*max)[Z] = tip->v[Z] + f;
    /* 2nd end ellipse */
    z = w1[Z] * mag_h;		/* Z part */
    tmp = magsq_c * w1[X] * w1[X] + magsq_d * w1[Y] * w1[Y];
    if (tmp > SMALL)
	f = sqrt(tmp);		/* XY part */
    else
	f = 0;
    if (tip->v[Z] - f + z < (*min)[Z])
	(*min)[Z] = tip->v[Z] - f + z;
    if (tip->v[Z] + f + z > (*max)[Z])
	(*max)[Z] = tip->v[Z] + f + z;

    return 0;
}