Пример #1
0
int
nonplanar(			/* are vertices non-planar? */
	int	ac,
	char	**av
)
{
	VNDX	vi;
	RREAL	*p0, *p1;
	FVECT	v1, v2, nsum, newn;
	double	d;
	int	i;

	if (!cvtndx(vi, av[0]))
		return(0);
	if (!flatten && vi[2] >= 0)
		return(1);		/* has interpolated normals */
	if (ac < 4)
		return(0);		/* it's a triangle! */
					/* set up */
	p0 = vlist[vi[0]];
	if (!cvtndx(vi, av[1]))
		return(0);		/* error gets caught later */
	nsum[0] = nsum[1] = nsum[2] = 0.;
	p1 = vlist[vi[0]];
	fvsum(v2, p1, p0, -1.0);
	for (i = 2; i < ac; i++) {
		VCOPY(v1, v2);
		if (!cvtndx(vi, av[i]))
			return(0);
		p1 = vlist[vi[0]];
		fvsum(v2, p1, p0, -1.0);
		fcross(newn, v1, v2);
		if (normalize(newn) == 0.0) {
			if (i < 3)
				return(1);	/* can't deal with this */
			fvsum(nsum, nsum, nsum, 1./(i-2));
			continue;
		}
		d = fdot(newn,nsum);
		if (d >= 0) {
			if (d < (1.0-FTINY)*(i-2))
				return(1);
			fvsum(nsum, nsum, newn, 1.0);
		} else {
			if (d > -(1.0-FTINY)*(i-2))
				return(1);
			fvsum(nsum, nsum, newn, -1.0);
		}
	}
	return(0);
}
static uint32_t
radial_compute_color (double                    a,
		      double                    b,
		      double                    c,
		      double                    inva,
		      double                    dr,
		      double                    mindr,
		      pixman_gradient_walker_t *walker,
		      pixman_repeat_t           repeat)
{
    /*
     * In this function error propagation can lead to bad results:
     *  - discr can have an unbound error (if b*b-a*c is very small),
     *    potentially making it the opposite sign of what it should have been
     *    (thus clearing a pixel that would have been colored or vice-versa)
     *    or propagating the error to sqrtdiscr;
     *    if discr has the wrong sign or b is very small, this can lead to bad
     *    results
     *
     *  - the algorithm used to compute the solutions of the quadratic
     *    equation is not numerically stable (but saves one division compared
     *    to the numerically stable one);
     *    this can be a problem if a*c is much smaller than b*b
     *
     *  - the above problems are worse if a is small (as inva becomes bigger)
     */
    double discr;

    if (a == 0)
    {
	double t;

	if (b == 0)
	    return 0;

	t = pixman_fixed_1 / 2 * c / b;
	if (repeat == PIXMAN_REPEAT_NONE)
	{
	    if (0 <= t && t <= pixman_fixed_1)
		return _pixman_gradient_walker_pixel (walker, t);
	}
	else
	{
	    if (t * dr >= mindr)
		return _pixman_gradient_walker_pixel (walker, t);
	}

	return 0;
    }

    discr = fdot (b, a, 0, b, -c, 0);
    if (discr >= 0)
    {
	double sqrtdiscr, t0, t1;

	sqrtdiscr = sqrt (discr);
	t0 = (b + sqrtdiscr) * inva;
	t1 = (b - sqrtdiscr) * inva;

	/*
	 * The root that must be used is the biggest one that belongs
	 * to the valid range ([0,1] for PIXMAN_REPEAT_NONE, any
	 * solution that results in a positive radius otherwise).
	 *
	 * If a > 0, t0 is the biggest solution, so if it is valid, it
	 * is the correct result.
	 *
	 * If a < 0, only one of the solutions can be valid, so the
	 * order in which they are tested is not important.
	 */
	if (repeat == PIXMAN_REPEAT_NONE)
	{
	    if (0 <= t0 && t0 <= pixman_fixed_1)
		return _pixman_gradient_walker_pixel (walker, t0);
	    else if (0 <= t1 && t1 <= pixman_fixed_1)
		return _pixman_gradient_walker_pixel (walker, t1);
	}
	else
	{
	    if (t0 * dr >= mindr)
		return _pixman_gradient_walker_pixel (walker, t0);
	    else if (t1 * dr >= mindr)
		return _pixman_gradient_walker_pixel (walker, t1);
	}
    }

    return 0;
}
static uint32_t *
radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
{
    /*
     * Implementation of radial gradients following the PDF specification.
     * See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference
     * Manual (PDF 32000-1:2008 at the time of this writing).
     *
     * In the radial gradient problem we are given two circles (c₁,r₁) and
     * (c₂,r₂) that define the gradient itself.
     *
     * Mathematically the gradient can be defined as the family of circles
     *
     *     ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
     *
     * excluding those circles whose radius would be < 0. When a point
     * belongs to more than one circle, the one with a bigger t is the only
     * one that contributes to its color. When a point does not belong
     * to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0).
     * Further limitations on the range of values for t are imposed when
     * the gradient is not repeated, namely t must belong to [0,1].
     *
     * The graphical result is the same as drawing the valid (radius > 0)
     * circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient
     * is not repeated) using SOURCE operator composition.
     *
     * It looks like a cone pointing towards the viewer if the ending circle
     * is smaller than the starting one, a cone pointing inside the page if
     * the starting circle is the smaller one and like a cylinder if they
     * have the same radius.
     *
     * What we actually do is, given the point whose color we are interested
     * in, compute the t values for that point, solving for t in:
     *
     *     length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
     *
     * Let's rewrite it in a simpler way, by defining some auxiliary
     * variables:
     *
     *     cd = c₂ - c₁
     *     pd = p - c₁
     *     dr = r₂ - r₁
     *     length(t·cd - pd) = r₁ + t·dr
     *
     * which actually means
     *
     *     hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr
     *
     * or
     *
     *     ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
     *
     * If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes:
     *
     *     (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
     *
     * where we can actually expand the squares and solve for t:
     *
     *     t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
     *       = r₁² + 2·r₁·t·dr + t²·dr²
     *
     *     (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
     *         (pdx² + pdy² - r₁²) = 0
     *
     *     A = cdx² + cdy² - dr²
     *     B = pdx·cdx + pdy·cdy + r₁·dr
     *     C = pdx² + pdy² - r₁²
     *     At² - 2Bt + C = 0
     *
     * The solutions (unless the equation degenerates because of A = 0) are:
     *
     *     t = (B ± ⎷(B² - A·C)) / A
     *
     * The solution we are going to prefer is the bigger one, unless the
     * radius associated to it is negative (or it falls outside the valid t
     * range).
     *
     * Additional observations (useful for optimizations):
     * A does not depend on p
     *
     * A < 0 <=> one of the two circles completely contains the other one
     *   <=> for every p, the radiuses associated with the two t solutions
     *       have opposite sign
     */
    pixman_image_t *image = iter->image;
    int x = iter->x;
    int y = iter->y;
    int width = iter->width;
    uint32_t *buffer = iter->buffer;

    gradient_t *gradient = (gradient_t *)image;
    radial_gradient_t *radial = (radial_gradient_t *)image;
    uint32_t *end = buffer + width;
    pixman_gradient_walker_t walker;
    pixman_vector_t v, unit;

    /* reference point is the center of the pixel */
    v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
    v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
    v.vector[2] = pixman_fixed_1;

    _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);

    if (image->common.transform)
    {
	if (!pixman_transform_point_3d (image->common.transform, &v))
	    return iter->buffer;

	unit.vector[0] = image->common.transform->matrix[0][0];
	unit.vector[1] = image->common.transform->matrix[1][0];
	unit.vector[2] = image->common.transform->matrix[2][0];
    }
    else
    {
	unit.vector[0] = pixman_fixed_1;
	unit.vector[1] = 0;
	unit.vector[2] = 0;
    }

    if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1)
    {
	/*
	 * Given:
	 *
	 * t = (B ± ⎷(B² - A·C)) / A
	 *
	 * where
	 *
	 * A = cdx² + cdy² - dr²
	 * B = pdx·cdx + pdy·cdy + r₁·dr
	 * C = pdx² + pdy² - r₁²
	 * det = B² - A·C
	 *
	 * Since we have an affine transformation, we know that (pdx, pdy)
	 * increase linearly with each pixel,
	 *
	 * pdx = pdx₀ + n·ux,
	 * pdy = pdy₀ + n·uy,
	 *
	 * we can then express B, C and det through multiple differentiation.
	 */
	pixman_fixed_32_32_t b, db, c, dc, ddc;

	/* warning: this computation may overflow */
	v.vector[0] -= radial->c1.x;
	v.vector[1] -= radial->c1.y;

	/*
	 * B and C are computed and updated exactly.
	 * If fdot was used instead of dot, in the worst case it would
	 * lose 11 bits of precision in each of the multiplication and
	 * summing up would zero out all the bit that were preserved,
	 * thus making the result 0 instead of the correct one.
	 * This would mean a worst case of unbound relative error or
	 * about 2^10 absolute error
	 */
	b = dot (v.vector[0], v.vector[1], radial->c1.radius,
		 radial->delta.x, radial->delta.y, radial->delta.radius);
	db = dot (unit.vector[0], unit.vector[1], 0,
		  radial->delta.x, radial->delta.y, 0);

	c = dot (v.vector[0], v.vector[1],
		 -((pixman_fixed_48_16_t) radial->c1.radius),
		 v.vector[0], v.vector[1], radial->c1.radius);
	dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0],
		  2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1],
		  0,
		  unit.vector[0], unit.vector[1], 0);
	ddc = 2 * dot (unit.vector[0], unit.vector[1], 0,
		       unit.vector[0], unit.vector[1], 0);

	while (buffer < end)
	{
	    if (!mask || *mask++)
	    {
		*buffer = radial_compute_color (radial->a, b, c,
						radial->inva,
						radial->delta.radius,
						radial->mindr,
						&walker,
						image->common.repeat);
	    }

	    b += db;
	    c += dc;
	    dc += ddc;
	    ++buffer;
	}
    }
    else
    {
	/* projective */
	/* Warning:
	 * error propagation guarantees are much looser than in the affine case
	 */
	while (buffer < end)
	{
	    if (!mask || *mask++)
	    {
		if (v.vector[2] != 0)
		{
		    double pdx, pdy, invv2, b, c;

		    invv2 = 1. * pixman_fixed_1 / v.vector[2];

		    pdx = v.vector[0] * invv2 - radial->c1.x;
		    /*    / pixman_fixed_1 */

		    pdy = v.vector[1] * invv2 - radial->c1.y;
		    /*    / pixman_fixed_1 */

		    b = fdot (pdx, pdy, radial->c1.radius,
			      radial->delta.x, radial->delta.y,
			      radial->delta.radius);
		    /*  / pixman_fixed_1 / pixman_fixed_1 */

		    c = fdot (pdx, pdy, -radial->c1.radius,
			      pdx, pdy, radial->c1.radius);
		    /*  / pixman_fixed_1 / pixman_fixed_1 */

		    *buffer = radial_compute_color (radial->a, b, c,
						    radial->inva,
						    radial->delta.radius,
						    radial->mindr,
						    &walker,
						    image->common.repeat);
		}
		else
		{
		    *buffer = 0;
		}
	    }

	    ++buffer;

	    v.vector[0] += unit.vector[0];
	    v.vector[1] += unit.vector[1];
	    v.vector[2] += unit.vector[2];
	}
    }

    iter->y++;
    return iter->buffer;
}
Пример #4
0
static uint32_t
radial_compute_color (double                    a,
		      double                    b,
		      double                    c,
		      double                    inva,
		      double                    dr,
		      double                    mindr,
		      pixman_gradient_walker_t *walker,
		      pixman_repeat_t           repeat)
{
    /*
     * In this function error propagation can lead to bad results:
     *  - det can have an unbound error (if b*b-a*c is very small),
     *    potentially making it the opposite sign of what it should have been
     *    (thus clearing a pixel that would have been colored or vice-versa)
     *    or propagating the error to sqrtdet;
     *    if det has the wrong sign or b is very small, this can lead to bad
     *    results
     *
     *  - the algorithm used to compute the solutions of the quadratic
     *    equation is not numerically stable (but saves one division compared
     *    to the numerically stable one);
     *    this can be a problem if a*c is much smaller than b*b
     *
     *  - the above problems are worse if a is small (as inva becomes bigger)
     */
    double det;

    if (a == 0)
    {
	double t;

	if (b == 0)
	    return 0;

	t = pixman_fixed_1 / 2 * c / b;
	if (repeat == PIXMAN_REPEAT_NONE)
	{
	    if (0 <= t && t <= pixman_fixed_1)
		return _pixman_gradient_walker_pixel (walker, t);
	}
	else
	{
	    if (t * dr > mindr)
		return _pixman_gradient_walker_pixel (walker, t);
	}

	return 0;
    }

    det = fdot (b, a, 0, b, -c, 0);
    if (det >= 0)
    {
	double sqrtdet, t0, t1;

	sqrtdet = sqrt (det);
	t0 = (b + sqrtdet) * inva;
	t1 = (b - sqrtdet) * inva;

	if (repeat == PIXMAN_REPEAT_NONE)
	{
	    if (0 <= t0 && t0 <= pixman_fixed_1)
		return _pixman_gradient_walker_pixel (walker, t0);
	    else if (0 <= t1 && t1 <= pixman_fixed_1)
		return _pixman_gradient_walker_pixel (walker, t1);
	}
	else
	{
	    if (t0 * dr > mindr)
		return _pixman_gradient_walker_pixel (walker, t0);
	    else if (t1 * dr > mindr)
		return _pixman_gradient_walker_pixel (walker, t1);
	}
    }

    return 0;
}
Пример #5
0
double llsfit( int N, double (*f)(double,int), int D, double x[], double y[],
	double w[], double A[], int order[], double WORK[] )
    {
    int d, n, m, mmax, RUN ;
    double chi, nchi, inner, norm, isave, nsave ;

    for( RUN = 0 ; RUN <= 1 ; RUN++ )
	{

	/* initialize order */

	for( n = 0 ; n < N ; n++ )
	    order[n] = n ;

	/* initialize the vectors */

	for( n = 0 ; n < N ; n++ )
	    {
	    for( d = 0 ; d < D ; d++ )
		vec(n,d) = (*f)( x[d], n ) ;
	    }

	/* initialize the data */

	for( d = 0 ; d < D ; d++ )
	    data(d) = y[d] ;

	if( RUN )
	    {

	/* figure out an a posteriori ordering */

	    for( n = 0 ; n < N ; n++ )
		B(0,n) = A[n] * A[n] * fdot( D, w, &vec(n,0), &vec(n,0) ) ;

	    for( n = 0 ; n < N ; n++ )
		{
		chi = B( 0, order[n] ) ;
		mmax = n ;
		for( m = n + 1 ; m < N ; m++ )
		    {
		    if( B( 0, order[m] ) > chi )
			{
			mmax = m ;
			chi = B( 0, order[m] ) ;
			}
		    }
		m = order[n] ;
		order[n] = order[mmax] ;
		order[mmax] = m ;
		}
	    }

	/* loop through each orthogonal function */

	for( n = 0 ; n < N ; n++ )
	    {

	    if( !RUN )				/* figure out an order */
		{

	/* figure out an a priori ordering */

		mmax = n ;
		chi = isave = nsave = 0.0 ;
		for( m = n ; m < N ; m++ )
		    {
		    inner = fdot( D, w, &vec(m,0), &data(0) ) ;
		    norm = fdot( D, w, &vec(m,0), &vec(m,0) ) ;
		    fortho( D, &work(0), &data(0), &vec(m,0), inner / norm ) ;
		    nchi = fdot( D, w, &work(0), &work(0) ) ;
		    if( !chi || (nchi < chi) )
			{
			chi = nchi ;
			mmax = m ;
			isave = inner ;
			nsave = norm ;
			}
		    }
		m = order[n] ;
		order[n] = order[mmax] ;
		order[mmax] = m ;
		inner = isave ;
		norm = nsave ;
		}
	    else				/* use given order */
		{
		inner = fdot( D, w, &vec(n,0), &data(0) ) ;
		norm = fdot( D, w, &vec(n,0), &vec(n,0) ) ;
		}

	/* subtract this vector from the data */

	    A[ order[n] ] = inner / norm ;
	    fortho( D, &data(0), &data(0), &vec(n,0), inner / norm ) ;

	/* orthogonalize the remaining vectors */

	    for( m = n + 1 ; m < N ; m++ )
		{
		inner = fdot( D, w, &vec(n,0), &vec(m,0) ) ;
		B( order[n], order[m] ) = inner / norm ;
		fortho( D, &vec(m,0), &vec(m,0), &vec(n,0), inner / norm ) ;
		}
	    }

	/* reassemble A in the original coordinate system */

	for( n = N - 1 ; n >= 0 ; n-- )
	for( m = n + 1 ; m < N ; m++ )
	    A[ order[n] ] -= B( order[n], order[m] ) * A[ order[m] ] ;
	}

	/* compute and return rms */

    return sqrt( fdot( D, w, &data(0), &data(0) ) / D ) ;
    }