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; }
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; }
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 ) ; }