예제 #1
0
static cairo_status_t
line_to (void *closure,
	 const cairo_point_t *point)
{
    struct stroker *stroker = closure;
    cairo_stroke_face_t start;
    cairo_point_t *p1 = &stroker->current_face.point;
    cairo_slope_t dev_slope;

    stroker->has_initial_sub_path = TRUE;

    if (p1->x == point->x && p1->y == point->y)
	return CAIRO_STATUS_SUCCESS;

#if DEBUG
    _cairo_contour_add_point (&stroker->path, point);
#endif

    _cairo_slope_init (&dev_slope, p1, point);
    compute_face (p1, &dev_slope, stroker, &start);

    if (stroker->has_current_face) {
	int clockwise = _cairo_slope_compare (&stroker->current_face.dev_vector,
					      &start.dev_vector);
	if (clockwise) {
	    clockwise = clockwise < 0;
	    /* Join with final face from previous segment */
	    if (! within_tolerance (&stroker->current_face.ccw, &start.ccw,
				    stroker->contour_tolerance) ||
		! within_tolerance (&stroker->current_face.cw, &start.cw,
				    stroker->contour_tolerance))
	    {
		outer_join (stroker, &stroker->current_face, &start, clockwise);
		inner_join (stroker, &stroker->current_face, &start, clockwise);
	    }
	}
    } else {
	if (! stroker->has_first_face) {
	    /* Save sub path's first face in case needed for closing join */
	    stroker->first_face = start;
	    stroker->has_first_face = TRUE;
	}
	stroker->has_current_face = TRUE;

	contour_add_point (stroker, &stroker->cw, &start.cw);
	contour_add_point (stroker, &stroker->ccw, &start.ccw);
    }

    stroker->current_face = start;
    stroker->current_face.point = *point;
    stroker->current_face.ccw.x += dev_slope.dx;
    stroker->current_face.ccw.y += dev_slope.dy;
    stroker->current_face.cw.x += dev_slope.dx;
    stroker->current_face.cw.y += dev_slope.dy;

    contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
    contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);

    return CAIRO_STATUS_SUCCESS;
}
예제 #2
0
    // Check for equality.
    // Return number of mismatches greater than epsilon.
    virtual idx_t compare(const GenericGridBase<T>* ref, T epsilon,
                           int maxPrint = 0,
                           std::ostream& os = std::cerr) const {

        auto ref1 = dynamic_cast<const GenericGrid1d*>(ref);
        if (!ref1) {
            os << "** type mismatch against GenericGrid1d." << endl;
            return 1;
        }

        // Quick check for errors.
        idx_t errs = count_diffs(*ref, epsilon);

        // Run detailed comparison if any errors found.
        if (errs > 0 && maxPrint) {
            int p = 0;
            for (idx_t i1 = 0; i1 < get_d1(); i1++) {
                T te = (*this)(i1);
                T re = (*ref1)(i1);
                if (!within_tolerance(te, re, epsilon)) {
                    p++;
                    if (p < maxPrint)
                        os << "** mismatch at (" << i1 << "): " <<
                            te << " != " << re << std::endl;
                    else if (p == maxPrint)
                        os << "** Additional errors not printed." << std::endl;
                    else
                        goto done;
                }
            }
        }

    done:
        return errs;
    }
예제 #3
0
    // Check for equality.
    // Return number of mismatches greater than epsilon.
    virtual idx_t compare(const GenericGridBase<T>* ref, T epsilon,
                           int maxPrint = 0,
                           std::ostream& os = std::cerr) const {

        auto ref1 = dynamic_cast<const GenericGrid0d*>(ref);
        if (!ref1) {
            os << "** type mismatch against GenericGrid0d." << endl;
            return 1;
        }

        // Quick check for errors.
        idx_t errs = count_diffs(*ref, epsilon);

        // Run detailed comparison if any errors found.
        if (errs > 0 && maxPrint) {
            T te = (*this)();
            T re = (*ref1)();
            if (!within_tolerance(te, re, epsilon)) {
                os << "** scalar mismatch: " <<
                    te << " != " << re << std::endl;
            }
        }

        return errs;
    }
예제 #4
0
static void
contour_add_point (struct stroker *stroker,
		   struct stroke_contour *c,
		   const cairo_point_t *point)
{
    if (! within_tolerance (point, _cairo_contour_last_point (&c->contour),
			stroker->contour_tolerance))
	_cairo_contour_add_point (&c->contour, point);
    //*_cairo_contour_last_point (&c->contour) = *point;
}
예제 #5
0
    // Check for equality.
    // Return number of mismatches greater than epsilon.
    virtual idx_t count_diffs(const GenericGridBase<T>& ref, T epsilon) const {
        idx_t errs = 0;

        // Count abs diffs > epsilon.
#pragma omp parallel for reduction(+:errs)
        for (idx_t ai = 0; ai < get_num_elems(); ai++) {
            if (!within_tolerance(_elems[ai], ref._elems[ai], epsilon))
                errs++;
        }

        return errs;
    }
예제 #6
0
static void
outer_close (struct stroker *stroker,
	     const cairo_stroke_face_t *in,
	     const cairo_stroke_face_t *out)
{
    const cairo_point_t	*inpt, *outpt;
    struct stroke_contour *outer;
    int	clockwise;

    if (in->cw.x == out->cw.x && in->cw.y == out->cw.y &&
	in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y)
    {
	return;
    }

    clockwise = join_is_clockwise (in, out);
    if (clockwise) {
	inpt = &in->cw;
	outpt = &out->cw;
	outer = &stroker->cw;
    } else {
	inpt = &in->ccw;
	outpt = &out->ccw;
	outer = &stroker->ccw;
    }

    if (within_tolerance (inpt, outpt, stroker->contour_tolerance)) {
	*_cairo_contour_first_point (&outer->contour) =
	    *_cairo_contour_last_point (&outer->contour);
	return;
    }

    switch (stroker->style.line_join) {
    case CAIRO_LINE_JOIN_ROUND:
	/* construct a fan around the common midpoint */
	if ((in->dev_slope.x * out->dev_slope.x +
	     in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
	{
	    add_fan (stroker,
		     &in->dev_vector, &out->dev_vector, &in->point,
		     clockwise, outer);
	    break;
	}

    case CAIRO_LINE_JOIN_MITER:
    default: {
	/* dot product of incoming slope vector with outgoing slope vector */
	double	in_dot_out = in->dev_slope.x * out->dev_slope.x +
			     in->dev_slope.y * out->dev_slope.y;
	double	ml = stroker->style.miter_limit;

	/* Check the miter limit -- lines meeting at an acute angle
	 * can generate long miters, the limit converts them to bevel
	 *
	 * Consider the miter join formed when two line segments
	 * meet at an angle psi:
	 *
	 *	   /.\
	 *	  /. .\
	 *	 /./ \.\
	 *	/./psi\.\
	 *
	 * We can zoom in on the right half of that to see:
	 *
	 *	    |\
	 *	    | \ psi/2
	 *	    |  \
	 *	    |   \
	 *	    |    \
	 *	    |     \
	 *	  miter    \
	 *	 length     \
	 *	    |        \
	 *	    |        .\
	 *	    |    .     \
	 *	    |.   line   \
	 *	     \    width  \
	 *	      \           \
	 *
	 *
	 * The right triangle in that figure, (the line-width side is
	 * shown faintly with three '.' characters), gives us the
	 * following expression relating miter length, angle and line
	 * width:
	 *
	 *	1 /sin (psi/2) = miter_length / line_width
	 *
	 * The right-hand side of this relationship is the same ratio
	 * in which the miter limit (ml) is expressed. We want to know
	 * when the miter length is within the miter limit. That is
	 * when the following condition holds:
	 *
	 *	1/sin(psi/2) <= ml
	 *	1 <= ml sin(psi/2)
	 *	1 <= ml² sin²(psi/2)
	 *	2 <= ml² 2 sin²(psi/2)
	 *				2·sin²(psi/2) = 1-cos(psi)
	 *	2 <= ml² (1-cos(psi))
	 *
	 *				in · out = |in| |out| cos (psi)
	 *
	 * in and out are both unit vectors, so:
	 *
	 *				in · out = cos (psi)
	 *
	 *	2 <= ml² (1 - in · out)
	 *
	 */
	if (2 <= ml * ml * (1 + in_dot_out)) {
	    double		x1, y1, x2, y2;
	    double		mx, my;
	    double		dx1, dx2, dy1, dy2;
	    double		ix, iy;
	    double		fdx1, fdy1, fdx2, fdy2;
	    double		mdx, mdy;

	    /*
	     * we've got the points already transformed to device
	     * space, but need to do some computation with them and
	     * also need to transform the slope from user space to
	     * device space
	     */
	    /* outer point of incoming line face */
	    x1 = _cairo_fixed_to_double (inpt->x);
	    y1 = _cairo_fixed_to_double (inpt->y);
	    dx1 = in->dev_slope.x;
	    dy1 = in->dev_slope.y;

	    /* outer point of outgoing line face */
	    x2 = _cairo_fixed_to_double (outpt->x);
	    y2 = _cairo_fixed_to_double (outpt->y);
	    dx2 = out->dev_slope.x;
	    dy2 = out->dev_slope.y;

	    /*
	     * Compute the location of the outer corner of the miter.
	     * That's pretty easy -- just the intersection of the two
	     * outer edges.  We've got slopes and points on each
	     * of those edges.  Compute my directly, then compute
	     * mx by using the edge with the larger dy; that avoids
	     * dividing by values close to zero.
	     */
	    my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
		  (dx1 * dy2 - dx2 * dy1));
	    if (fabs (dy1) >= fabs (dy2))
		mx = (my - y1) * dx1 / dy1 + x1;
	    else
		mx = (my - y2) * dx2 / dy2 + x2;

	    /*
	     * When the two outer edges are nearly parallel, slight
	     * perturbations in the position of the outer points of the lines
	     * caused by representing them in fixed point form can cause the
	     * intersection point of the miter to move a large amount. If
	     * that moves the miter intersection from between the two faces,
	     * then draw a bevel instead.
	     */

	    ix = _cairo_fixed_to_double (in->point.x);
	    iy = _cairo_fixed_to_double (in->point.y);

	    /* slope of one face */
	    fdx1 = x1 - ix; fdy1 = y1 - iy;

	    /* slope of the other face */
	    fdx2 = x2 - ix; fdy2 = y2 - iy;

	    /* slope from the intersection to the miter point */
	    mdx = mx - ix; mdy = my - iy;

	    /*
	     * Make sure the miter point line lies between the two
	     * faces by comparing the slopes
	     */
	    if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
		slope_compare_sgn (fdx2, fdy2, mdx, mdy))
	    {
		cairo_point_t p;

		p.x = _cairo_fixed_from_double (mx);
		p.y = _cairo_fixed_from_double (my);

		*_cairo_contour_last_point (&outer->contour) = p;
		*_cairo_contour_first_point (&outer->contour) = p;
		return;
	    }
	}
	break;
    }

    case CAIRO_LINE_JOIN_BEVEL:
	break;
    }
    contour_add_point (stroker, outer, outpt);
}
예제 #7
0
static double test_gradients(Crystal *cr, double incr_val, int refine,
                             const char *str, const char *file,
                             PartialityModel pmodel, int quiet, int plot)
{
	Reflection *refl;
	RefListIterator *iter;
	long double *vals[3];
	int i;
	int *valid;
	int nref;
	int n_good, n_invalid, n_small, n_nan, n_bad;
	RefList *reflections;
	FILE *fh = NULL;
	int ntot = 0;
	double total = 0.0;
	char tmp[32];
	double *vec1;
	double *vec2;
	int n_line;
	double cc;

	reflections = find_intersections(crystal_get_image(cr), cr, pmodel);
	crystal_set_reflections(cr, reflections);

	nref = num_reflections(reflections);
	if ( nref < 10 ) {
		ERROR("Too few reflections found.  Failing test by default.\n");
		return 0.0;
	}

	vals[0] = malloc(nref*sizeof(long double));
	vals[1] = malloc(nref*sizeof(long double));
	vals[2] = malloc(nref*sizeof(long double));
	if ( (vals[0] == NULL) || (vals[1] == NULL) || (vals[2] == NULL) ) {
		ERROR("Couldn't allocate memory.\n");
		return 0.0;
	}

	valid = malloc(nref*sizeof(int));
	if ( valid == NULL ) {
		ERROR("Couldn't allocate memory.\n");
		return 0.0;
	}
	for ( i=0; i<nref; i++ ) valid[i] = 1;

	scan_partialities(reflections, reflections, valid, vals, 1, pmodel);

	calc_either_side(cr, incr_val, valid, vals, refine, pmodel);

	if ( plot ) {
		snprintf(tmp, 32, "gradient-test-%s.dat", file);
		fh = fopen(tmp, "w");
	}

	vec1 = malloc(nref*sizeof(double));
	vec2 = malloc(nref*sizeof(double));
	if ( (vec1 == NULL) || (vec2 == NULL) ) {
		ERROR("Couldn't allocate memory.\n");
		return 0.0;
	}

	n_invalid = 0;  n_good = 0;
	n_nan = 0;  n_small = 0;  n_bad = 0;  n_line = 0;
	i = 0;
	for ( refl = first_refl(reflections, &iter);
	      refl != NULL;
	      refl = next_refl(refl, iter) )
	{

		long double grad1, grad2, grad;
		double cgrad;
		signed int h, k, l;

		get_indices(refl, &h, &k, &l);

		if ( !valid[i] ) {
			n_invalid++;
			i++;
		} else {

			double r1, r2, p;

			grad1 = (vals[1][i] - vals[0][i]) / incr_val;
			grad2 = (vals[2][i] - vals[1][i]) / incr_val;
			grad = (grad1 + grad2) / 2.0;
			i++;

			cgrad = p_gradient(cr, refine, refl, pmodel);

			get_partial(refl, &r1, &r2, &p);

			if ( isnan(cgrad) ) {
				n_nan++;
				continue;
			}

			if ( plot ) {
				fprintf(fh, "%e %Le\n", cgrad, grad);
			}

			vec1[n_line] = cgrad;
			vec2[n_line] = grad;
			n_line++;

			if ( (fabs(cgrad) < 5e-8) && (fabs(grad) < 5e-8) ) {
				n_small++;
				continue;
			}

			total += fabs(cgrad - grad);
			ntot++;

			if ( !within_tolerance(grad, cgrad, 5.0)
			  || !within_tolerance(cgrad, grad, 5.0) )
			{

				if ( !quiet ) {
					STATUS("!- %s %3i %3i %3i"
					       " %10.2Le %10.2e ratio = %5.2Lf"
					       " %10.2e %10.2e\n",
					       str, h, k, l, grad, cgrad,
					       cgrad/grad, r1, r2);
				}
				n_bad++;

			} else {

				//STATUS("OK %s %3i %3i %3i"
				//       " %10.2Le %10.2e ratio = %5.2Lf"
				//       " %10.2e %10.2e\n",
				//       str, h, k, l, grad, cgrad, cgrad/grad,
				//       r1, r2);

				n_good++;

			}

		}

	}

	STATUS("%3s: %3i within 5%%, %3i outside, %3i nan, %3i invalid, "
	       "%3i small. ", str, n_good, n_bad, n_nan, n_invalid, n_small);

	if ( plot ) {
		fclose(fh);
	}

	cc = gsl_stats_correlation(vec1, 1, vec2, 1, n_line);
	STATUS("CC = %+f\n", cc);
	return cc;
}