static void set_and_post_mask(struct MTouch *mt, DeviceIntPtr dev, mstime_t delta_t){ struct Gestures* gs; ValuatorMask* mask; float speed_factor; gs = &mt->gs; mask = mt->vm; valuator_mask_zero(mask); if (gs->move_dx) valuator_mask_set_double(mask, 0, gs->move_dx); if (gs->move_dy) valuator_mask_set_double(mask, 1, gs->move_dy); switch (gs->move_type){ case GS_SCROLL: case GS_SWIPE3: case GS_SWIPE4: //case GS_MOVE: case GS_NONE: /* Only scroll, or swipe or move can trigger coasting right now */ /* Continue coasting if enabled */ speed_factor = (mt->cfg.scroll_coast.num_of_ticks - gs->scroll_coast_tick_no) / (float)(mt->cfg.scroll_coast.num_of_ticks); if (ABSVAL(gs->scroll_speed_x) > mt->cfg.scroll_coast.min_speed) valuator_mask_set_double(mask, 2, gs->scroll_speed_x * delta_t * speed_factor); if (ABSVAL(gs->scroll_speed_y) > mt->cfg.scroll_coast.min_speed) valuator_mask_set_double(mask, 3, gs->scroll_speed_y * delta_t * speed_factor); break; default: /* Any other movement/gesture type will break coasting. */ mt->gs.scroll_speed_y = mt->gs.scroll_speed_x = 0.0f; break; } xf86PostMotionEventM(dev, Relative, mask); /* Once posted, we can clear the move variables */ gs->move_dx = gs->move_dy = 0; }
/* * This must be FAST! * * new_line is a boolean that tells us if the last time this was * called the line terminated, and we need to start a * new line. This must be initialized to 1 on the first call. * * Quickplot must cull when drawing lines, after zooming, * so that we do not try to draw lines "out of bounds". * Like for example, after zooming we may have points that * are way out side the drawing area. Drawing lines with * end points outside the drawing area will/may give undefined * results. We have seen examples without culling where * the lines look like they are drawn from random end points, * when that was clearly not what we wanted to see. Even * though cario uses doubles it does not map end points of * lines that are outside the drawing area to edges where * we would expect to see them, at least not all the time. * * Besides that, it turns out that culling out lines * is faster than trying to draw them. Which is what * you would expect. * * In this function, we find the points on the drawing area * edges where the line would intersect and draw lines "in * bounds" to represent lines that would otherwise be drawn * off the drawing area. */ static inline void CullDrawLine(struct qp_graph *gr, int *new_line, /* if (*new_line) then we start a * new line, else we continue the last * line */ /* We treat the drawing area (x0,y0) to (x1,y1) like it is * (minusLWidthP1,minusLWidthP1) to (widthPlus,heightPlus) * though the real drawing area is smaller we use a larger * area in order to catch edges of thick lines that may * pass through the edge of the real drawing area. */ double minusLWidthP1, double widthPlus, double heightPlus, /* fromX, fromY and toX, toY are in pixels that define * a line that we wish to draw. But if they are * not in the drawing region we must find the line that * they would make though the drawing region by finding * side intersection points. You can not draw lines from * points like (x,y) 10, -1e10 to 10, 1e10 but we can find * edge intersections of a line that we can draw from. * The number 1e10 is to large to be used to draw lines * with. */ double fromX, double fromY, double toX, double toY) { if(!is_good_double(fromX) || !is_good_double(fromY) || !is_good_double(toX) || !is_good_double(toY)) { /* We need to do this uncommon case first because bad * values can not be used well in the code that follows. */ *new_line = 1; return; } // The common cases come first. // If both points are in the drawing area if(fromX > minusLWidthP1 && fromX < widthPlus && toX > minusLWidthP1 && toX < widthPlus && fromY > minusLWidthP1 && fromY < heightPlus && toY > minusLWidthP1 && toY < heightPlus) { gr->DrawLine(gr, new_line, fromX, fromY, toX, toY); return; } // Do some quick Culls for both points way off to one side: right, // left, up, or down. This will Cull MOST points out! Speed is // the result. //points all on right side, if((fromX >= widthPlus && toX >= widthPlus) || // on the left side, (fromX <= minusLWidthP1 && toX <= minusLWidthP1) || // on top (up), (fromY <= minusLWidthP1 && toY <= minusLWidthP1) || // or on bottom (down) (fromY >= heightPlus && toY >= heightPlus)) { /* we start over the next line draw */ *new_line = 1; return; // Culled } // now both points are not in the drawing area (maybe one point is). // Below we refer to the line formed by the two points fromX, fromY and // toX, toY as "line" or "the line" ... /* close to horizontal lines are more common than close * to vertical lines */ if(ABSVAL(toX - fromX) > 0.01) { double m; /* slope of the line */ m = (toY - fromY)/(toX - fromX); if(ABSVAL(m) < 1.0e+5) { /* The slope is not large */ double a; a = fromY - m * fromX; /* the equation for the line is: Y = m * X + a */ if(fromX < minusLWidthP1) { fromX = minusLWidthP1; fromY = m * fromX + a; } else if(fromX > widthPlus) { fromX = widthPlus; fromY = m * fromX + a; } if(toX < minusLWidthP1) { toX = minusLWidthP1; toY = m * toX + a; } else if(toX > widthPlus) { toX = widthPlus; toY = m * toX + a; } if((fromY < minusLWidthP1 && toY < minusLWidthP1) || (fromY > heightPlus && toY > heightPlus)) { /* The line is above or below the drawing area */ *new_line = 1; return; // Culled } if(toY < minusLWidthP1) { toY = minusLWidthP1; toX = (toY - a)/m; } else if(toY > heightPlus) { toY = heightPlus; toX = (toY - a)/m; } if(fromY < minusLWidthP1) { fromY = minusLWidthP1; fromX = (fromY - a)/m; } else if(fromY > heightPlus) { fromY = heightPlus; fromX = (fromY - a)/m; } gr->DrawLine(gr, new_line, fromX, fromY, toX, toY); return; } } /* Now we do the more vertical line case */ if(ABSVAL(toY - fromY) > 0.01) { double u; /* inverse slope of the line */ u = (toX - fromX)/(toY - fromY); if(ABSVAL(u) < 1.0e5) { /* The inverse slope is not too large */ double b; b = fromX - u * fromY; /* the equation for the line is: X = u * Y + b */ if(fromY < minusLWidthP1) { fromY = minusLWidthP1; fromX = u * fromY + b; } else if(fromY > heightPlus) { fromY = heightPlus; fromX = u * fromY + b; } if(toY < minusLWidthP1) { toY = minusLWidthP1; toX = u * toY + b; } else if(toY > heightPlus) { toY = heightPlus; toX = u * toY + b; } if((fromX < minusLWidthP1 && toX < minusLWidthP1) || (fromX > widthPlus && toX > widthPlus)) { /* The line is to the left or right of the drawing area */ *new_line = 1; return; // Culled } /* The line goes through the drawing area */ if(toX < minusLWidthP1) { toX = minusLWidthP1; toY = (toX - b)/u; } else if(toX > widthPlus) { toX = widthPlus; toY = (toX - b)/u; } if(fromX < minusLWidthP1) { fromX = minusLWidthP1; fromY = (fromX - b)/u; } else if(fromX > widthPlus) { fromX = widthPlus; fromY = (fromX - b)/u; } gr->DrawLine(gr, new_line, fromX, fromY, toX, toY); return; } } /* The points are close to each other and not in the * drawing area */ *new_line = 1; // Culled }
static inline void DrawYGrid(cairo_t *cr, PangoLayout *pangolayout, struct qp_graph *gr, struct qp_plot *z, int64_t xmin_mat, int64_t xmax_mat, int64_t xinc, double xpow_part, int64_t ymin_mat, int64_t ymax_mat, int64_t yinc, double ypow_part, int width, int height, int view_width) { /******************************************************/ /* find where to put the value text for y lines */ /******************************************************/ int64_t xLabel_start, xLabel_inc, xLabel_max; gint x_ylinetext; int64_t i, max; char FMT[FORMAT_LEN]; x_ylinetext = qp_plot_get_xpixel(z, (xmin_mat + xinc*0.2)*xpow_part); if(x_ylinetext < 3) x_ylinetext = qp_plot_get_xpixel(z, (xmin_mat + xinc*1.2)*xpow_part); if(gr->grid_numbers) { /* We can get better X position precision if we * increase the range of the numbers in X. */ xmin_mat *= 100; xmax_mat *= 100; xinc *= 100; xpow_part /= 100; if(gr->same_x_scale) { xLabel_inc = (qp_plot_get_xval(z, view_width) - qp_plot_get_xval(z, 0))/ xpow_part; // make xLabel_inc a multiple of xinc if(xLabel_inc < 14*xinc/10) xLabel_inc = xinc; else if(xLabel_inc < 24*xinc/10) xLabel_inc = 2*xinc; else if(xLabel_inc < 34*xinc/10) xLabel_inc = 3*xinc; else xLabel_inc -= xLabel_inc%xinc; xLabel_start = qp_plot_get_xval(z, gr->pixbuf_x - 14 /* padding from grid line */)/ xpow_part; xLabel_start -= ((int64_t)(xLabel_start - xmin_mat))%xinc; if(qp_plot_get_xpixel(z, xLabel_start*xpow_part) < gr->pixbuf_x - 14 /* padding */) xLabel_start += xinc; xLabel_start += - ((int64_t)(xLabel_start - xmin_mat)) + ((int64_t)(xLabel_start - xmin_mat))%xLabel_inc; xLabel_max = xmax_mat; xLabel_max -= ((xLabel_max - xLabel_start)%xLabel_inc); } else { xLabel_inc = ( qp_plot_get_xval(z, view_width) - qp_plot_get_xval(z, 0) )/xpow_part; xLabel_start = qp_plot_get_xval(z, gr->pixbuf_x)/xpow_part; xLabel_start += - ((int64_t)(xLabel_start - xmin_mat)) + ((int64_t)(xLabel_start - xmin_mat))%xLabel_inc; xLabel_max = xmax_mat; xLabel_max -= ((xLabel_max - xLabel_start)%xLabel_inc); } } max = ABSVAL(ymin_mat); if(ABSVAL(ymax_mat) > max) max = ABSVAL(ymax_mat); if(max/yinc > 10000) { strcpy(FMT, H_GRID_PRINT_FORMAT); //printf("y high res\n"); } else strcpy(FMT, L_GRID_PRINT_FORMAT); /**************************************************** * draw y labels ****************************************************/ if(gr->grid_numbers) { cairo_set_source_rgba(cr, gr->grid_text_color.r, gr->grid_text_color.g, gr->grid_text_color.b, gr->grid_text_color.a); for(i=ymin_mat; i <= ymax_mat; i += yinc) { char str[64]; int y; int64_t j; snprintf(str,64, FMT, i*ypow_part); //snprintf(str,64, "%*.*g", digit_count,digit_count, i*ypow_part); //printf(GRID_PRINT_FORMAT" ", str); y = qp_plot_get_ypixel(z, i*ypow_part); for(j = xLabel_start; j <= xLabel_max; j += xLabel_inc) { cairo_translate(cr, qp_plot_get_xpixel(z, j*xpow_part) + gr->grid_line_width/2 + 10, y+ gr->grid_line_width/2); pango_layout_set_text(pangolayout, str, -1); pango_cairo_update_layout(cr, pangolayout); pango_cairo_show_layout(cr, pangolayout); /* clear the translation */ cairo_identity_matrix(cr); } } } /**************************************************** * draw horizontal lines at y values ****************************************************/ cairo_set_source_rgba(cr, gr->grid_line_color.r, gr->grid_line_color.g, gr->grid_line_color.b, gr->grid_line_color.a); cairo_set_line_width(cr, gr->grid_line_width); for(i=ymin_mat; i <= ymax_mat; i += yinc) { int y; y = qp_plot_get_ypixel(z, i*ypow_part); // - gr->grid_line_width; cairo_move_to(cr, 0, y); cairo_line_to(cr, width, y); } /* draw the lines */ cairo_stroke(cr); }
/* This is not too trival. Number round-off must be avoided. We * require the grid lines be drawn with the same method that the plot * points plot lines, so that they are not off by one pixel. We must * not have plots that miss-lead the user in any way. */ static void PreDrawGrid(struct qp_graph *gr, struct qp_plot *z, int64_t *xmin_mat, int64_t *xmax_mat, int64_t *xinc, double *xpow_part, int64_t *ymin_mat, int64_t *ymax_mat, int64_t *yinc, double *ypow_part, int width, int height) { double xmin = qp_plot_get_xval(z, 0); double xmax = qp_plot_get_xval(z, width); double ymax = qp_plot_get_yval(z, 0); double ymin = qp_plot_get_yval(z, height); /***************************************************/ /* get the x value lines calculated */ /***************************************************/ //DEBUG("pix width=%d values xmin=%g xmax=%g\n", width, xmin, xmax); //DEBUG("pix height=%d values ymin=%g ymax=%g\n", height, ymin, ymax); double delta; /* change in x values between vertical grid lines */ delta = (xmax - xmin)/(2 + ((double) width/gr->grid_x_space)); //printf("xdelta=%g gr->grid_x_space=%d\n", delta, //gr->grid_x_space); gint delta_p = (gint) log10(ABSVAL(delta) > SMALL_NUM ? ABSVAL(delta) : SMALL_NUM); if(delta_p <= 0) delta_p--; *xpow_part = POW(TEN, delta_p); //printf("xdelta_p=%d xpow_part=%g\n", delta_p, *xpow_part); { // strip off the round-off error off of xpow_part. char s[16]; //for example: xpow_part=0.20005465 --> // s=0.20 --> xpow_part=0.2000000 sprintf(s, TWO_DIGIT_FORMAT, *xpow_part); sscanf(s, SCAN_FORMAT, xpow_part); //printf("s=%s xpow_part=%.15g\n",s, xpow_part); } *xmin_mat = (int64_t) (xmin/(*xpow_part)); *xmax_mat = (int64_t) (xmax/(*xpow_part)); //printf(" xmin = %ldx10%+d xmax = %ldx10%+d\n", // *xmin_mat, delta_p, *xmax_mat, delta_p); if(width > gr->grid_x_space) *xinc = (int64_t) ((*xmax_mat - *xmin_mat)/ ((double) width/ gr->grid_x_space)); else *xinc = *xmax_mat - *xmin_mat; //printf(" xinc=%ld\n", *xinc); // round to 1, 2, 5, times 10^N if (*xinc < (int64_t) 2) *xinc = 1; else if(*xinc < (int64_t) 5) *xinc = 2; else if(*xinc < (int64_t) 10) *xinc = 5; else if(*xinc < (int64_t) 20) *xinc = 10; else if(*xinc < (int64_t) 50) *xinc = 20; else if(*xinc < (int64_t) 100) *xinc = 50; else if(*xinc < (int64_t) 200) *xinc = 100; else *xinc = 200; //DEBUG("xinc=%ld xmin_mat=%ld\n", *xinc, *xmin_mat); if(*xmin_mat > (int64_t) 0 && (*xmin_mat)%(*xinc)) *xmin_mat -= (*xmin_mat)%(*xinc); else if(*xmin_mat < (int64_t) 0 && (*xmin_mat)%(*xinc)) *xmin_mat -= *xinc + (*xmin_mat)%(*xinc); //printf(" xinc=%ld\n", *xinc); /***************************************************/ /* get the y value lines calculated */ /***************************************************/ delta = (ymax - ymin)/(2 + ((double) height/ gr->grid_y_space)); delta_p = (gint) log10(ABSVAL(delta) > SMALL_NUM ? ABSVAL(delta) : SMALL_NUM); if(delta_p <= 0) delta_p--; //printf("ydelta_p=%d\n", delta_p); *ypow_part = POW(TEN, delta_p); { // strip off the round-off error off of ypow_part. char s[16]; //for example: ypow_part=0.20005465 --> // s=0.20 --> ypow_part=0.2000000 sprintf(s, TWO_DIGIT_FORMAT, *ypow_part); sscanf(s, SCAN_FORMAT, ypow_part); } *ymin_mat = (int64_t) (ymin/(*ypow_part)); *ymax_mat = (int64_t) (ymax/(*ypow_part)); //printf(" ymin = %ldx10%+d ymax = %ldx10%+d\n", // *ymin_mat, delta_p, *ymax_mat, delta_p); if(height > gr->grid_y_space) *yinc = (int64_t) ((*ymax_mat - *ymin_mat)/ ((double) height/ gr->grid_y_space)); else *yinc = *ymax_mat - *ymin_mat; if (*yinc < (int64_t) 2) *yinc = 1; else if(*yinc < (int64_t) 5) *yinc = 2; else if(*yinc < (int64_t) 10) *yinc = 5; else if(*yinc < (int64_t) 20) *yinc = 10; else if(*yinc < (int64_t) 50) *yinc = 20; else if(*yinc < (int64_t) 100) *yinc = 50; else if(*yinc < (int64_t) 200) *yinc = 100; else *yinc = 200; //printf("yinc=%ld\n", *yinc); if(*ymin_mat > (int64_t) 0 && (*ymin_mat)%(*yinc)) *ymin_mat -= (*ymin_mat)%(*yinc); else if(*ymin_mat < (int64_t) 0 && (*ymin_mat)%(*yinc)) *ymin_mat -= *yinc + (*ymin_mat)%(*yinc); }
static inline void DrawXGrid(cairo_t *cr, PangoLayout *pangolayout, struct qp_graph *gr, struct qp_plot *z, int64_t xmin_mat, int64_t xmax_mat, int64_t xinc, double xpow_part, int64_t ymin_mat, int64_t ymax_mat, int64_t yinc, double ypow_part, int width, int height, int view_height) { /******************************************************/ /* find where to put the value text for x lines */ /******************************************************/ int64_t yLabel_start, yLabel_inc, yLabel_max; int64_t i, max; char FMT[FORMAT_LEN]; if(gr->grid_numbers) { /* We can get better Y position precision if we * increase the range of the numbers in Y. */ yinc *= 100; ymin_mat *= 100; ymax_mat *= 100; ypow_part /= 100; if(gr->same_y_scale) { yLabel_inc = (qp_plot_get_yval(z, 0) - qp_plot_get_yval(z, view_height))/ ypow_part; // make yLabel_inc a multiple of yinc if(yLabel_inc < 14*yinc/10) yLabel_inc = yinc; else if(yLabel_inc < 24*yinc/10) yLabel_inc = 2*yinc; else if(yLabel_inc < 34*yinc/10) yLabel_inc = 3*yinc; else yLabel_inc -= yLabel_inc%yinc; yLabel_start = qp_plot_get_yval(z, view_height - 15 + gr->pixbuf_y)/ ypow_part; yLabel_start -= ((int64_t)(yLabel_start - ymin_mat + yinc*0.5))%yinc; if(qp_plot_get_ypixel(z, yLabel_start*ypow_part) > view_height + gr->pixbuf_y - 10/* font height */ - 3 /* padding */) yLabel_start += yinc; yLabel_start += - ((int64_t)(yLabel_start - ymin_mat + yinc*0.5)) + ((int64_t)(yLabel_start - ymin_mat + yinc*0.5))%yLabel_inc; yLabel_max = ymax_mat - yinc*0.5; yLabel_max -= ((yLabel_max - yLabel_start)% yLabel_inc); } else { yLabel_inc = (qp_plot_get_yval(z,0) - qp_plot_get_yval(z,view_height))/ ypow_part; yLabel_start = qp_plot_get_yval(z,view_height - 15 + gr->pixbuf_y)/ ypow_part; yLabel_start += - ((int64_t)(yLabel_start - ymin_mat)) + ((int64_t)(yLabel_start - ymin_mat))%yLabel_inc; yLabel_max = ymax_mat; yLabel_max -= ((yLabel_max - yLabel_start)% yLabel_inc); } } max = ABSVAL(xmin_mat); if(ABSVAL(xmax_mat) > max) max = ABSVAL(xmax_mat); if(max/xinc > 10000) { strcpy(FMT, H_GRID_PRINT_FORMAT); //printf("x high res\n"); } else strcpy(FMT, L_GRID_PRINT_FORMAT); /**************************************************** * draw x labels ****************************************************/ if(gr->grid_numbers) { cairo_set_source_rgba(cr, gr->grid_text_color.r, gr->grid_text_color.g, gr->grid_text_color.b, gr->grid_text_color.a); for(i=xmin_mat; i <= xmax_mat; i += xinc) { char str[64]; int x; int64_t j; snprintf(str,64, FMT, i*xpow_part); //printf(" xpow_part=%.15g\n",xpow_part); //printf(GRID_PRINT_FORMAT" ", i*xpow_part); x = qp_plot_get_xpixel(z, i*xpow_part); for(j = yLabel_start; j <= yLabel_max; j += yLabel_inc) { cairo_translate(cr, x+3+ gr->grid_line_width/2, qp_plot_get_ypixel(z, j*ypow_part) - 5 /* 1/2 font height */); pango_layout_set_text(pangolayout, str, -1); pango_cairo_update_layout(cr, pangolayout); pango_cairo_show_layout(cr, pangolayout); /* clear the translation */ cairo_identity_matrix(cr); //printf("%g\n", j*ypow_part); } } } /**************************************************** * draw vertical lines at x values ****************************************************/ cairo_set_source_rgba(cr, gr->grid_line_color.r, gr->grid_line_color.g, gr->grid_line_color.b, gr->grid_line_color.a); cairo_set_line_width(cr, gr->grid_line_width); for(i=xmin_mat; i <= xmax_mat; i += xinc) { int x; x = qp_plot_get_xpixel(z, i*xpow_part); // gr->grid_line_width; cairo_move_to(cr, x, 0); cairo_line_to(cr, x, height); } /* draw the lines */ cairo_stroke(cr); }