void gt_graphics_cairo_draw_caret(GtGraphics *gg, double x, double y, double width,double height, ArrowStatus arrow_status, double arrow_width, double stroke_width, GtColor stroke_color) { GtGraphicsCairo *g = gt_graphics_cairo_cast(gg); gt_assert(g); /* save cairo context */ cairo_save(g->cr); cairo_rectangle(g->cr, g->margin_x, g->margin_y, g->width-2*g->margin_x, g->height-2*g->margin_y); cairo_clip(g->cr); /* create caret path */ switch (arrow_status) { case ARROW_RIGHT: if (gt_double_smaller_double(0, width - arrow_width)) { width -= arrow_width; cairo_move_to(g->cr, x, y + (height/2)); cairo_line_to(g->cr, x + (width/2), y); cairo_line_to(g->cr, x + width, y + (height/2)); cairo_line_to(g->cr, x + width + arrow_width, y + (height/2)); /* add arrowhead */ cairo_move_to(g->cr, x + width, y); cairo_line_to(g->cr, x + width + arrow_width, y + height / 2); cairo_line_to(g->cr, x + width, y + height); } break; case ARROW_LEFT: if (gt_double_smaller_double(0, width - arrow_width)) { width -= arrow_width; /* draw arrowhead */ cairo_move_to(g->cr, x + arrow_width , y); cairo_line_to(g->cr, x, y + (height/2)); cairo_line_to(g->cr, x + arrow_width, y + height); cairo_move_to(g->cr, x, y + (height/2)); cairo_line_to(g->cr, x + arrow_width, y + (height/2)); cairo_line_to(g->cr, x + arrow_width + (width/2), y); cairo_line_to(g->cr, x + arrow_width + width, y + (height/2)); } break; case ARROW_BOTH: /* XXX */ case ARROW_NONE: cairo_move_to(g->cr, x, y + (height/2)); cairo_line_to(g->cr, x + (width/2), y); cairo_line_to(g->cr, x + width, y + (height/2)); } /* draw caret */ cairo_set_line_width(g->cr, stroke_width); cairo_set_source_rgba(g->cr, stroke_color.red, stroke_color.green, stroke_color.blue, stroke_color.alpha); cairo_stroke(g->cr); /* restore cairo context */ cairo_restore(g->cr); }
int calculate_drawing_range(GtLineBreakerCaptions *lbc, GtDrawingRange *rng, GtBlock* block, GtError *err) { double textwidth = 0.0; GtDrawingRange drange; gt_assert(block && lbc); drange = gt_coords_calc_generic_range(gt_block_get_range(block), gt_layout_get_range(lbc->layout)); drange.start *= lbc->width-2*lbc->margins; drange.end *= lbc->width-2*lbc->margins; if (gt_block_get_caption(block)) { textwidth = gt_text_width_calculator_get_text_width( gt_layout_get_twc(lbc->layout), gt_str_get(gt_block_get_caption(block)), err); if (gt_double_smaller_double(textwidth, 0)) return -1; if (gt_double_smaller_double(gt_drawing_range_length(drange), textwidth)) drange.end = drange.start + textwidth; } rng->start = drange.start; rng->end = drange.end; return 0; }
int gt_drawing_range_compare(GtDrawingRange range_a, GtDrawingRange range_b) { gt_assert(range_a.start <= range_a.end && range_b.start <= range_b.end); if (gt_double_equals_double(range_a.start, range_b.start) && gt_double_equals_double(range_a.end, range_b.end)) return 0; /* range_a == range_b */ if (gt_double_smaller_double(range_a.start, range_b.start) || (gt_double_equals_double(range_a.start, range_b.start) && gt_double_smaller_double(range_a.end, range_b.end))) return -1; /* range_a < range_b */ return 1; /* range_a > range_b */ }
void gt_graphics_cairo_draw_dashes(GtGraphics *gg, double x, double y, double width, double height, ArrowStatus arrow_status, double arrow_width, double stroke_width, GtColor stroke_color) { GtGraphicsCairo *g = gt_graphics_cairo_cast(gg); double dashes[] = {2.0}; gt_assert(g); /* save cairo context */ cairo_save(g->cr); cairo_rectangle(g->cr, g->margin_x, g->margin_y, g->width-2*g->margin_x, g->height-2*g->margin_y); cairo_clip(g->cr); cairo_set_line_width(g->cr, stroke_width); cairo_set_source_rgba(g->cr, stroke_color.red, stroke_color.green, stroke_color.blue, stroke_color.alpha); /* create arrowhead path */ if (gt_double_smaller_double(0, width - arrow_width)) { switch (arrow_status) { case ARROW_RIGHT: cairo_move_to(g->cr, rnd_to_nhalf(x + width - arrow_width), y); cairo_line_to(g->cr, rnd_to_nhalf(x + width), y + height / 2); cairo_line_to(g->cr, rnd_to_nhalf(x + width - arrow_width), y + height); /* draw arrowhead */ cairo_stroke(g->cr); break; case ARROW_LEFT: cairo_move_to(g->cr, rnd_to_nhalf(x + arrow_width), y); cairo_line_to(g->cr, rnd_to_nhalf(x), y + height / 2); cairo_line_to(g->cr, rnd_to_nhalf(x + arrow_width), y + height); /* draw arrowhead */ cairo_stroke(g->cr); break; case ARROW_BOTH: cairo_move_to(g->cr, rnd_to_nhalf(x + width - arrow_width), y); cairo_line_to(g->cr, rnd_to_nhalf(x + width), y + height / 2); cairo_line_to(g->cr, rnd_to_nhalf(x + width - arrow_width), y + height); cairo_move_to(g->cr, rnd_to_nhalf(x + arrow_width), y); cairo_line_to(g->cr, rnd_to_nhalf(x), y + height / 2); cairo_line_to(g->cr, rnd_to_nhalf(x + arrow_width), y + height); cairo_stroke(g->cr); break; case ARROW_NONE: break; } } /* draw dashes */ cairo_set_dash(g->cr, dashes, 1, (double) 0); cairo_move_to(g->cr, rnd_to_nhalf(x), rnd_to_nhalf(y+(height/2))); cairo_rel_line_to(g->cr, rnd_to_nhalf(width), 0); cairo_stroke(g->cr); /* restore cairo context */ cairo_restore(g->cr); }
int gt_mathsupport_unit_test(GtError *err) { int had_err = 0; double less_than_epsilon = 0.0000000000000001; gt_error_check(err); gt_ensure(had_err, !gt_double_equals_one(1.1)); gt_ensure(had_err, gt_double_equals_one(1)); gt_ensure(had_err, gt_double_equals_one(1+less_than_epsilon)); gt_ensure(had_err, !gt_double_equals_one(-1-less_than_epsilon)); gt_ensure(had_err, !gt_double_equals_double(1.0, 2.0)); gt_ensure(had_err, !gt_double_equals_double(-1.0, 1.0)); gt_ensure(had_err, !gt_double_equals_double(1.0, -1.0)); gt_ensure(had_err, !gt_double_equals_double(-1.0, 1+less_than_epsilon)); gt_ensure(had_err, !gt_double_equals_double(1.0, 1.1)); gt_ensure(had_err, gt_double_equals_double(1.0, 1+less_than_epsilon)); gt_ensure(had_err, gt_double_equals_double(1.0, 1.0)); gt_ensure(had_err, gt_double_equals_double(0.0, 0.0)); gt_ensure(had_err, gt_double_equals_double(-1.0, -1.0)); gt_ensure(had_err, gt_double_equals_double(-1.0+less_than_epsilon, -1.0)); gt_ensure(had_err, gt_double_equals_double(-1.0, -1.0+less_than_epsilon)); gt_ensure(had_err, gt_double_equals_double(1.0+less_than_epsilon, 1.0)); gt_ensure(had_err, gt_double_equals_double(1.0, 1.0+less_than_epsilon)); gt_ensure(had_err, gt_double_compare(1.0, 1.0) == 0); gt_ensure(had_err, gt_double_compare(1.0, 1.1) < 0); gt_ensure(had_err, gt_double_compare(1.1, 1.0) > 0); gt_ensure(had_err, gt_double_compare(1.1, -1.0) > 0); gt_ensure(had_err, gt_double_compare(-1.1, -1.0) < 0); gt_ensure(had_err, gt_double_compare(1+less_than_epsilon, 1.0) == 0); gt_ensure(had_err, gt_double_compare(1+less_than_epsilon, -1.0) > 0); gt_ensure(had_err, gt_double_compare(-1+less_than_epsilon, -1.0) == 0); gt_ensure(had_err, gt_double_compare(-1+less_than_epsilon, 1.0) < 0); gt_ensure(had_err, gt_double_smaller_double(1.0, 1.1)); gt_ensure(had_err, gt_double_smaller_double(-1.0, 1.1)); gt_ensure(had_err, gt_double_smaller_double(-1.1, -1.0)); gt_ensure(had_err, !gt_double_smaller_double(-1.0, -1.1)); gt_ensure(had_err, !gt_double_smaller_double(1.0-less_than_epsilon, 1.0)); return had_err; }
void gt_graphics_cairo_draw_curve_data(GtGraphics *gg, double x, double y, GtColor color, double data[], unsigned long ndata, GtRange valrange, unsigned long height) { unsigned long i, rnglen; double xpos; GtGraphicsCairo *g; g = gt_graphics_cairo_cast(gg); xpos = (((double)g->width-2*g->margin_x)/((double)ndata-1)); rnglen = valrange.end - valrange.start; cairo_save(g->cr); cairo_move_to(g->cr, x, y+(1-(data[0]-valrange.start)/(double) rnglen)*height); for (i=1;i<ndata;i++) { double val, pval; if (gt_double_smaller_double(data[i], valrange.start) || gt_double_smaller_double(valrange.end, data[i])) break; val = (double) (data[i]-valrange.start)/(double) rnglen; pval = (double) (data[i-1]-valrange.start)/(double) rnglen; gt_assert(val <= 1 && val >= 0 && pval >= 0 && pval <= 1); cairo_curve_to(g->cr, x + ((i-0.5) * xpos), y + (1-pval) * height, x + ((i-0.5) * xpos), y + (1-val) * height, x + (i * xpos), y + (1-val) * height); } cairo_set_source_rgba(g->cr, color.red, color.green, color.blue, color.alpha); cairo_stroke(g->cr); cairo_restore(g->cr); }
void gt_graphics_cairo_draw_text(GtGraphics *gg, double x, double y, const char *text) { GtGraphicsCairo *g = gt_graphics_cairo_cast(gg); cairo_text_extents_t ext; gt_assert(g && text); cairo_text_extents(g->cr, text, &ext); if (gt_double_smaller_double(g->width, x+ext.width)) return; cairo_set_source_rgb(g->cr, 0, 0, 0); cairo_move_to(g->cr, x, y); cairo_show_text(g->cr, text); }
double gt_graphics_cairo_get_text_width(GtGraphics *gg, const char* text) { PangoRectangle rect; GtGraphicsCairo *g = gt_graphics_cairo_cast(gg); gt_assert(g && text && g->layout); pango_layout_set_text(g->layout, text, -1); /* get text extents */ pango_layout_get_pixel_extents(g->layout, &rect, NULL); gt_assert(gt_double_smaller_double(0, rect.width)); return rect.width; }
/* calculate divergence */ double gt_divergence(double E, /* relative error for divergence calculation */ double T, /* absolute error for exp shulen*/ double M, /* minimum for logarithm */ double threshold, /* abs error for divergence */ double shulen, GtUword subjectLength, double gc, double *ln_n_fac, GtUword n_s) { double p, q, du, dl, dm, d, exp_shulen; double *s1; s1 = gt_calloc((size_t) n_s + 1, sizeof (double)); p = gc / 2; q = (1.0 - gc) / 2.0; du = 0.0; dl = 1.0 - (2 * p * p + 2 * q * q); /* dl < 0.75 */ while (gt_double_smaller_double(threshold, (dl - du) / 2.0)) { dm = (du + dl) / 2.0; exp_shulen = expShulen(T, M, dm, p, subjectLength, ln_n_fac, s1, n_s); if (gt_double_smaller_double(shulen, exp_shulen)) du = dm; else dl = dm; /* test the relative error between du and dl; if it is smaller than some * threshold, then break !! */ if (fabs (dl - du) / dl <= E) break; } d = (du + dl) / 2.0; gt_free(s1); return d; }
static int check_width(unsigned int width, GtStyle *style, GtError *err) { int had_err = 0; double margins = MARGINS_DEFAULT; (void) gt_style_get_num(style, "format", "margins", &margins, NULL); if (gt_double_smaller_double(width - 2*margins, 0)) { gt_error_set(err, "layout width must at least be twice the x-margin size " "(2*%.1f=%.1f) but was %u", margins, 2*margins, width); had_err = -1; } return had_err; }
void gt_graphics_cairo_draw_text(GtGraphics *gg, double x, double y, const char *text) { PangoRectangle ink; GtGraphicsCairo *g = gt_graphics_cairo_cast(gg); gt_assert(g && text && g->layout); pango_layout_set_text(g->layout, text, -1); /* get text extents */ pango_layout_get_pixel_extents(g->layout, &ink, NULL); if (gt_double_smaller_double(g->width, x+ink.width)) return; cairo_set_source_rgb(g->cr, 0, 0, 0); cairo_move_to(g->cr, x, y-g->font_height); pango_cairo_show_layout(g->cr, g->layout); }
double gt_text_width_calculator_cairo_get_text_width(GtTextWidthCalculator *twc, const char *text, GT_UNUSED GtError *err) { GtTextWidthCalculatorCairo *twcc; PangoRectangle rect; gt_assert(twc && text); twcc = gt_text_width_calculator_cairo_cast(twc); /* redo layout */ pango_layout_set_text(twcc->layout, text, -1); /* get extents */ pango_layout_get_pixel_extents(twcc->layout, &rect, NULL); if (twcc->style) cairo_restore(twcc->context); gt_assert(gt_double_smaller_double(0, rect.width)); return rect.width; }
/* This function orders GtElements by z-index or type. This enables the sketch function to paint elements in a specific order based on their type (painter's algorithm-like) */ static int elemcmp(const void *a, const void *b, void *data) { const char *type_a, *type_b; double zindex_a = GT_UNDEF_DOUBLE, zindex_b= GT_UNDEF_DOUBLE; GtStyle *sty = (GtStyle*) data; GtElement *elem_a = *(GtElement**) a; GtElement *elem_b = *(GtElement**) b; type_a = gt_element_get_type(elem_a); type_b = gt_element_get_type(elem_b); /* same types are equal, no further action needed */ if (type_a == type_b) return 0; /* if not, then get z-index from style */ if (sty) { (void) gt_style_get_num(sty, type_a, "z_index", &zindex_a, NULL, NULL); (void) gt_style_get_num(sty, type_b, "z_index", &zindex_b, NULL, NULL); } /* only one is set -> put types with set z-indices always on top of others*/ if (zindex_a == GT_UNDEF_DOUBLE && zindex_b != GT_UNDEF_DOUBLE) return -1; if (zindex_b == GT_UNDEF_DOUBLE && zindex_a != GT_UNDEF_DOUBLE) return 1; /* none is set, fall back to default alphabetic ordering */ if (zindex_a == GT_UNDEF_DOUBLE && zindex_b == GT_UNDEF_DOUBLE) { if (strcmp(type_a, type_b) < 0) return 1; return -1; } /* both z-indices are set */ if (gt_double_equals_double(zindex_a, zindex_b)) return 0; if (gt_double_smaller_double(zindex_a, zindex_b)) return -1; return 1; }
int gt_block_get_max_height(const GtBlock *block, double *result, const GtStyle *sty, GtError *err) { GtUword max_height = 0; GtStyleQueryStatus rval = GT_STYLE_QUERY_OK; GtUword i; gt_assert(block && sty); for (i=0;i<gt_array_size(block->elements);i++) { GtElement *elem; double height = 0; elem = *(GtElement**) gt_array_get(block->elements, i); /* get default or image-wide bar height */ rval = gt_style_get_num(sty, "format", "bar_height", &height, NULL, err); switch (rval) { case GT_STYLE_QUERY_ERROR: return -1; break; /* should never reach this */ case GT_STYLE_QUERY_NOT_SET: height = BAR_HEIGHT_DEFAULT; break; default: /* do nothing */ break; } /* try to get type-specific bar height */ rval = gt_style_get_num(sty, gt_element_get_type(elem), "bar_height", &height, gt_element_get_node_ref(elem), err); if (rval == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_double_smaller_double(max_height, height)) max_height = height; } *result = max_height; return 0; }
void gt_firstcodes_spacelog_add(GtFirstcodesspacelog *fcsl, int line, const char *filename, bool add, const char *title, bool work, size_t size) { GtFirstcodespacelogentry *entry; size_t logspace; if (add) { entry = gt_spacelog_find(fcsl,title); if (entry != NULL) { if (entry->size != 0) { fprintf(stderr,"existing entry for title \"%s\"" "(from file %s, line %d) " "in spacelog entries must have size 0\n", title,filename,line); exit(GT_EXIT_PROGRAMMING_ERROR); } gt_spacelog_updateaddentry(entry,filename,line,title,size,work); } else { gt_spacelog_addentry(fcsl,filename,line,title,size,work); } if (work) { fcsl->workspace += size; } else { fcsl->splitspace += size; } gt_firstcodes_updatemax(fcsl); } else { entry = gt_spacelog_find(fcsl,title); if (entry == NULL) { fprintf(stderr,"cannot find title \"%s\" (from file %s, line %d) " "in spacelog entries\n",title,filename,line); (void) gt_firstcodes_spacelog_showentries(stderr,fcsl); exit(GT_EXIT_PROGRAMMING_ERROR); } if ((entry->work && !work) || (!entry->work && work)) { fprintf(stderr,"for title \"%s\" (from file %s, line %d) " "in spacelog entries: inconsistent work/splitassignment\n", title,filename,line); exit(GT_EXIT_PROGRAMMING_ERROR); } if (work) { if (entry->size > fcsl->workspace) { gt_firstcodes_subtract_error(title, filename, line, entry->size, true, fcsl->workspace); (void) gt_firstcodes_spacelog_showentries(stderr,fcsl); exit(GT_EXIT_PROGRAMMING_ERROR); } fcsl->workspace -= entry->size; } else { if (entry->size > fcsl->splitspace) { gt_firstcodes_subtract_error(title, filename, line, entry->size, false, fcsl->splitspace); (void) gt_firstcodes_spacelog_showentries(stderr,fcsl); exit(GT_EXIT_PROGRAMMING_ERROR); } fcsl->splitspace -= entry->size; } if (size > 0) { gt_spacelog_updateaddentry(entry,filename,line,title,size,work); if (work) { fcsl->workspace += size; } else { fcsl->splitspace += size; } gt_firstcodes_updatemax(fcsl); if (size > entry->size) { add = true; size -= entry->size; } else { size = entry->size - size; } } else { size = entry->size; entry->size = 0; } } logspace = fcsl->workspace+fcsl->splitspace; gt_log_log( #ifdef SKDEBUG "file %s, line %d: " #endif "%s %s= %.2f, %s, w=%.2f, s=%.2f, sum=%.2f MB", #ifdef SKDEBUG filename, line, #endif work ? "w" : "s", add ? "+" : "-", GT_MEGABYTES(size), title, GT_MEGABYTES(fcsl->workspace), GT_MEGABYTES(fcsl->splitspace), GT_MEGABYTES(logspace)); #ifdef SKDEBUG if (gt_ma_bookkeeping_enabled()) { unsigned long realspace = gt_ma_get_space_current() + gt_fa_get_space_current(); gt_log_log("current space usage %.2f MB (%.2f+%.2f)", GT_MEGABYTES(realspace), GT_MEGABYTES(gt_ma_get_space_current()), GT_MEGABYTES(gt_fa_get_space_current())); if (fcsl->calc_difference) { double percent_difference; if ((unsigned long) logspace > realspace) { fprintf(stderr,"overestimating logspace\n"); exit(GT_EXIT_PROGRAMMING_ERROR); } if (realspace >= 1000000UL) { /* printf("realspace=%lu,logspace=%lu\n",realspace, (unsigned long) logspace); */ percent_difference = 100.0 * (double) (realspace - logspace)/realspace; if (gt_double_larger_double(percent_difference,3.0)) { fprintf(stderr,"space difference of %.2f%% is too large\n", percent_difference); exit(GT_EXIT_PROGRAMMING_ERROR); } if (gt_double_smaller_double(fcsl->max_percent_difference, percent_difference)) { fcsl->max_percent_difference = percent_difference; } } } } #endif }
int gt_canvas_cairo_visit_block(GtCanvas *canvas, GtBlock *block, GtError *err) { int had_err = 0, arrow_status = ARROW_NONE; GtRange block_range; GtDrawingRange draw_range; GtColor grey, fillcolor, strokecolor; double block_start, block_width, bar_height = BAR_HEIGHT_DEFAULT, min_len_block = MIN_LEN_BLOCK_DEFAULT, arrow_width = ARROW_WIDTH_DEFAULT, stroke_width = STROKE_WIDTH_DEFAULT; const char *caption, *btype; GtStrand strand; double maxbarheight; btype = gt_block_get_type(block); gt_assert(canvas && block); grey.red = grey.green = grey.blue = DEFAULT_GREY_TONE; grey.alpha = 0.5; strand = gt_block_get_strand(block); block_range = gt_block_get_range(block); if (gt_block_get_max_height(block, &maxbarheight, canvas->pvt->sty, err)) { return -1; } if (gt_style_get_num(canvas->pvt->sty, "format", "bar_height", &bar_height, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num(canvas->pvt->sty, "format", "min_len_block", &min_len_block,NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num(canvas->pvt->sty, "format", "arrow_width", &arrow_width, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num(canvas->pvt->sty, "format", "stroke_width", &stroke_width, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_color_with_track(canvas->pvt->sty, btype, "stroke", &strokecolor, gt_block_get_top_level_feature(block), gt_track_get_title(canvas->pvt->current_track), err) == GT_STYLE_QUERY_ERROR) { return -1; } if (strand == GT_STRAND_REVERSE || strand == GT_STRAND_BOTH) arrow_status = ARROW_LEFT; if (strand == GT_STRAND_FORWARD || strand == GT_STRAND_BOTH) arrow_status = (arrow_status == ARROW_LEFT ? ARROW_BOTH : ARROW_RIGHT); /* calculate scaled drawing coordinates for this canvas */ draw_range = gt_coords_calc_generic_range(block_range, canvas->pvt->viewrange); draw_range.start *= canvas->pvt->width-2*canvas->pvt->margins; draw_range.end *= canvas->pvt->width-2*canvas->pvt->margins; block_start = draw_range.start + canvas->pvt->margins; block_width = draw_range.end - draw_range.start; /* draw block caption */ if (gt_block_caption_is_visible(block)) { caption = gt_str_get(gt_block_get_caption(block)); if (caption) { double theight = gt_graphics_get_text_height(canvas->pvt->g), captionspace = CAPTION_BAR_SPACE_DEFAULT; if (gt_style_get_num(canvas->pvt->sty, "format", "block_caption_space", &captionspace, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num(canvas->pvt->sty, "format", "block_caption_font_size", &theight, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } gt_graphics_set_font(canvas->pvt->g, "Sans", SLANT_NORMAL, WEIGHT_NORMAL, theight); gt_graphics_draw_text_clip(canvas->pvt->g, block_start, canvas->pvt->y - bar_height/2 - captionspace, caption); } } /* do not draw further details in very small blocks */ if (!gt_block_has_only_one_fullsize_element(block) && gt_double_smaller_double(block_width, min_len_block)) { /* optimise drawing for very narrow blocks, if <= 1px/pt width, draw as simple lines */ if (canvas->pvt->bt && draw_range.end-draw_range.start <= 1.1) { if (!gt_bittab_bit_is_set(canvas->pvt->bt, (unsigned long) draw_range.start)) { gt_graphics_draw_vertical_line(canvas->pvt->g, block_start, canvas->pvt->y - bar_height/2, strokecolor, bar_height, stroke_width); gt_bittab_set_bit(canvas->pvt->bt, (unsigned long) draw_range.start); } } else { if (gt_style_get_color_with_track(canvas->pvt->sty, btype, "fill", &fillcolor, gt_block_get_top_level_feature(block), gt_track_get_title(canvas->pvt->current_track), err) == GT_STYLE_QUERY_ERROR) { return -1; } gt_graphics_draw_box(canvas->pvt->g, block_start, canvas->pvt->y - bar_height/2, block_width, bar_height, fillcolor, arrow_status, arrow_width, stroke_width, strokecolor, true); /* draw arrowheads at clipped margins */ if (draw_range.clip == CLIPPED_LEFT || draw_range.clip == CLIPPED_BOTH) gt_graphics_draw_arrowhead(canvas->pvt->g, canvas->pvt->margins - 10, canvas->pvt->y - 4, grey, ARROW_LEFT); if (draw_range.clip == CLIPPED_RIGHT || draw_range.clip == CLIPPED_BOTH) gt_graphics_draw_arrowhead(canvas->pvt->g, canvas->pvt->width-canvas->pvt->margins + 10, canvas->pvt->y - 4, grey, ARROW_RIGHT); } /* register coordinates in GtImageInfo object if available */ if (canvas->pvt->ii) { GtRecMap *rm = gt_rec_map_new(block_start, canvas->pvt->y - bar_height/2, block_start + block_width, canvas->pvt->y + bar_height/2, (GtFeatureNode*) /* XXX */ gt_block_get_top_level_feature(block)); gt_image_info_add_rec_map(canvas->pvt->ii, rm); gt_rec_map_set_omitted_children(rm, true); } /* signal break */ return 1; } /* get stroke color */ if (gt_style_get_color(canvas->pvt->sty, "format", "default_stroke_color", &strokecolor, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } /* draw parent block boundaries */ gt_graphics_draw_dashes(canvas->pvt->g, block_start, canvas->pvt->y - bar_height/2, block_width, bar_height, ARROW_NONE, arrow_width, stroke_width, strokecolor); return had_err; }
void gt_graphics_cairo_draw_box(GtGraphics *gg, double x, double y, double width, double height, GtColor fill_color, ArrowStatus arrow_status, double arrow_width, double stroke_width, GtColor stroke_color, bool dashed) { GtGraphicsCairo *g = gt_graphics_cairo_cast(gg); double dashes[]={2.0}; bool widthdiff_geq0; gt_assert(g); /* save cairo context */ cairo_save(g->cr); cairo_rectangle(g->cr, rnd_to_nhalf(g->margin_x), g->margin_y, rnd_to_nhalf(g->width-2*g->margin_x), g->height-2*g->margin_y); cairo_clip(g->cr); widthdiff_geq0 = gt_double_smaller_double(0, width - arrow_width); /* construct shape of the box or arrow */ switch (arrow_status) { case ARROW_RIGHT: cairo_move_to(g->cr, rnd_to_nhalf(x), rnd_to_nhalf(y)); if (widthdiff_geq0) cairo_line_to(g->cr, x + width - arrow_width, rnd_to_nhalf(y)); cairo_line_to(g->cr, rnd_to_nhalf(x + width), rnd_to_nhalf(y + height / 2)); if (widthdiff_geq0) cairo_line_to(g->cr, x + width - arrow_width, rnd_to_nhalf(y + height)); cairo_line_to(g->cr, rnd_to_nhalf(x), rnd_to_nhalf(y + height)); cairo_close_path(g->cr); break; case ARROW_LEFT: cairo_move_to(g->cr, rnd_to_nhalf(x + width), rnd_to_nhalf(y)); if (widthdiff_geq0) { cairo_line_to(g->cr, rnd_to_nhalf(x + arrow_width), rnd_to_nhalf(y)); } cairo_line_to(g->cr, rnd_to_nhalf(x), rnd_to_nhalf(y + height / 2)); if (widthdiff_geq0) { cairo_line_to(g->cr, rnd_to_nhalf(x + arrow_width), rnd_to_nhalf(y + height)); } cairo_line_to(g->cr, rnd_to_nhalf(x + width), rnd_to_nhalf(y + height)); cairo_close_path(g->cr); break; case ARROW_BOTH: cairo_move_to(g->cr, rnd_to_nhalf(x), rnd_to_nhalf(y + height/2)); if (gt_double_smaller_double(width, 2*arrow_width)) { cairo_line_to(g->cr, rnd_to_nhalf(x + width/2), rnd_to_nhalf(y)); cairo_line_to(g->cr, rnd_to_nhalf(x + width), rnd_to_nhalf(y + height/2)); cairo_line_to(g->cr, rnd_to_nhalf(x + width/2), rnd_to_nhalf(y + height)); } else { cairo_line_to(g->cr, rnd_to_nhalf(x + arrow_width), rnd_to_nhalf(y)); cairo_line_to(g->cr, rnd_to_nhalf(x + width - arrow_width), rnd_to_nhalf(y)); cairo_line_to(g->cr, rnd_to_nhalf(x + width), rnd_to_nhalf(y + height/2)); cairo_line_to(g->cr, rnd_to_nhalf(x + width - arrow_width), rnd_to_nhalf(y + height)); cairo_line_to(g->cr, rnd_to_nhalf(x + arrow_width), y + height); } cairo_close_path(g->cr); break; case ARROW_NONE: cairo_rectangle(g->cr, rnd_to_nhalf(x), rnd_to_nhalf(y), width, height); } /* fill area */ cairo_set_source_rgba(g->cr, fill_color.red, fill_color.green, fill_color.blue, fill_color.alpha); cairo_fill_preserve(g->cr); /* draw outline */ cairo_set_line_width(g->cr, stroke_width); cairo_set_source_rgba(g->cr, stroke_color.red, stroke_color.green, stroke_color.blue, stroke_color.alpha); if (dashed) cairo_set_dash(g->cr, dashes, 1, (double) 0); cairo_stroke(g->cr); /* restore cairo context */ cairo_restore(g->cr); }
static int gt_sketch_page_runner(GT_UNUSED int argc, const char **argv, int parsed_args, void *tool_arguments, GtError *err) { SketchPageArguments *arguments = tool_arguments; int had_err = 0; GtFeatureIndex *features = NULL; GtRange qry_range, sequence_region_range; GtStyle *sty = NULL; GtStr *prog, *gt_style_file; GtDiagram *d = NULL; GtLayout *l = NULL; GtBioseq *bioseq = NULL; GtCanvas *canvas = NULL; const char *seqid = NULL, *outfile; unsigned long start, height, num_pages = 0; double offsetpos, usable_height; cairo_surface_t *surf = NULL; cairo_t *cr = NULL; GtTextWidthCalculator *twc; gt_error_check(err); features = gt_feature_index_memory_new(); if (cairo_version() < CAIRO_VERSION_ENCODE(1, 8, 6)) gt_warning("Your cairo library (version %s) is older than version 1.8.6! " "These versions contain a bug which may result in " "corrupted PDF output!", cairo_version_string()); /* get style */ sty = gt_style_new(err); if (gt_str_length(arguments->stylefile) == 0) { prog = gt_str_new(); gt_str_append_cstr_nt(prog, argv[0], gt_cstr_length_up_to_char(argv[0], ' ')); gt_style_file = gt_get_gtdata_path(gt_str_get(prog), err); gt_str_delete(prog); gt_str_append_cstr(gt_style_file, "/sketch/default.style"); } else { gt_style_file = gt_str_ref(arguments->stylefile); } had_err = gt_style_load_file(sty, gt_str_get(gt_style_file), err); outfile = argv[parsed_args]; if (!had_err) { /* get features */ had_err = gt_feature_index_add_gff3file(features, argv[parsed_args+1], err); if (!had_err && gt_str_length(arguments->seqid) == 0) { seqid = gt_feature_index_get_first_seqid(features); if (seqid == NULL) { gt_error_set(err, "GFF input file must contain a sequence region!"); had_err = -1; } } else if (!had_err && !gt_feature_index_has_seqid(features, gt_str_get(arguments->seqid))) { gt_error_set(err, "sequence region '%s' does not exist in GFF input file", gt_str_get(arguments->seqid)); had_err = -1; } else if (!had_err) seqid = gt_str_get(arguments->seqid); } /* set text */ if (gt_str_length(arguments->text) == 0) { gt_str_delete(arguments->text); arguments->text = gt_str_new_cstr(argv[parsed_args+1]); } if (!had_err) { /* set display range */ gt_feature_index_get_range_for_seqid(features, &sequence_region_range, seqid); qry_range.start = (arguments->range.start == GT_UNDEF_ULONG ? sequence_region_range.start : arguments->range.start); qry_range.end = (arguments->range.end == GT_UNDEF_ULONG ? sequence_region_range.end : arguments->range.end); /* set output format */ if (strcmp(gt_str_get(arguments->format), "pdf") == 0) { surf = cairo_pdf_surface_create(outfile, mm_to_pt(arguments->pwidth), mm_to_pt(arguments->pheight)); } else if (strcmp(gt_str_get(arguments->format), "ps") == 0) { surf = cairo_ps_surface_create(outfile, mm_to_pt(arguments->pwidth), mm_to_pt(arguments->pheight)); } gt_log_log("created page with %.2f:%.2f dimensions\n", mm_to_pt(arguments->pwidth), mm_to_pt(arguments->pheight)); offsetpos = TEXT_SPACER + arguments->theight + TEXT_SPACER; usable_height = mm_to_pt(arguments->pheight) - arguments->theight - arguments->theight - 4*TEXT_SPACER; if (gt_str_length(arguments->seqfile) > 0) { bioseq = gt_bioseq_new(gt_str_get(arguments->seqfile), err); } cr = cairo_create(surf); cairo_set_font_size(cr, 8); twc = gt_text_width_calculator_cairo_new(cr, sty); for (start = qry_range.start; start <= qry_range.end; start += arguments->width) { GtRange single_range; GtCustomTrack *ct = NULL; const char *seq; single_range.start = start; single_range.end = start + arguments->width; if (had_err) break; d = gt_diagram_new(features, seqid, &single_range, sty, err); if (!d) { had_err = -1; break; } if (bioseq) { seq = gt_bioseq_get_sequence(bioseq, 0); ct = gt_custom_track_gc_content_new(seq, gt_bioseq_get_sequence_length(bioseq, 0), 800, 70, 0.4, true); gt_diagram_add_custom_track(d, ct); } l = gt_layout_new_with_twc(d, mm_to_pt(arguments->width), sty, twc, err); had_err = gt_layout_get_height(l, &height, err); if (!had_err) { if (gt_double_smaller_double(usable_height - 10 - 2*TEXT_SPACER - arguments->theight, offsetpos + height)) { draw_header(cr, gt_str_get(arguments->text), argv[parsed_args+1], seqid, num_pages, mm_to_pt(arguments->pwidth), mm_to_pt(arguments->pheight), arguments->theight); cairo_show_page(cr); offsetpos = TEXT_SPACER + arguments->theight + TEXT_SPACER; num_pages++; } canvas = gt_canvas_cairo_context_new(sty, cr, offsetpos, mm_to_pt(arguments->pwidth), height, NULL, err); if (!canvas) had_err = -1; offsetpos += height; if (!had_err) had_err = gt_layout_sketch(l, canvas, err); } gt_canvas_delete(canvas); gt_layout_delete(l); gt_diagram_delete(d); if (ct) gt_custom_track_delete(ct); } draw_header(cr, gt_str_get(arguments->text), argv[parsed_args+1], seqid, num_pages, mm_to_pt(arguments->pwidth), mm_to_pt(arguments->pheight), arguments->theight); cairo_show_page(cr); num_pages++; gt_log_log("finished, should be %lu pages\n", num_pages); gt_text_width_calculator_delete(twc); cairo_destroy(cr); cairo_surface_flush(surf); cairo_surface_finish(surf); cairo_surface_destroy(surf); cairo_debug_reset_static_data(); if (bioseq) gt_bioseq_delete(bioseq); gt_style_delete(sty); gt_str_delete(gt_style_file); gt_feature_index_delete(features); } return had_err; }
int gt_canvas_cairo_visit_element(GtCanvas *canvas, GtElement *elem, GtError *err) { int had_err = 0, arrow_status = ARROW_NONE; GtRange elem_range = gt_element_get_range(elem); GtDrawingRange draw_range; double elem_start = GT_UNDEF_DOUBLE, elem_width = GT_UNDEF_DOUBLE, stroke_width = STROKE_WIDTH_DEFAULT, bar_height = BAR_HEIGHT_DEFAULT, arrow_width = ARROW_WIDTH_DEFAULT; GtColor elem_color, grey, fill_color; const char *type; GtStyleQueryStatus rval; GtStr *style; GtStrand strand = gt_element_get_strand(elem); gt_assert(canvas && elem); /* This shouldn't happen. */ if (!gt_range_overlap(&elem_range, &canvas->pvt->viewrange)) return -1; type = gt_element_get_type(elem); grey.red = grey.green = grey.blue = .85; grey.alpha = 0.5; /* get default or image-wide bar height */ if (gt_style_get_num(canvas->pvt->sty, "format", "bar_height", &bar_height, NULL, err) == GT_STYLE_QUERY_ERROR) { return -1; } /* try to get type-specific bar height */ if (gt_style_get_num_with_track(canvas->pvt->sty, type, "bar_height", &bar_height, gt_element_get_node_ref(elem), gt_track_get_title(canvas->pvt->current_track), err) == GT_STYLE_QUERY_ERROR) { return -1; } /* get default or image-wide arrow width */ if (gt_style_get_num(canvas->pvt->sty, "format", "arrow_width", &arrow_width, NULL, err)== GT_STYLE_QUERY_ERROR) { return -1; } /* try to get type-specific arrow width */ if (gt_style_get_num_with_track(canvas->pvt->sty, type, "arrow_width", &arrow_width, gt_element_get_node_ref(elem), gt_track_get_title(canvas->pvt->current_track), err) == GT_STYLE_QUERY_ERROR) { return -1; } if ((strand == GT_STRAND_REVERSE || strand == GT_STRAND_BOTH) /*&& delem == gt_dlist_first(elems)*/) arrow_status = ARROW_LEFT; if ((strand == GT_STRAND_FORWARD || strand == GT_STRAND_BOTH) /*&& gt_dlistelem_next(delem) == NULL*/) arrow_status = (arrow_status == ARROW_LEFT ? ARROW_BOTH : ARROW_RIGHT); gt_log_log("processing element from %lu to %lu, strand %d\n", elem_range.start, elem_range.end, (int) strand); draw_range = gt_coords_calc_generic_range(elem_range, canvas->pvt->viewrange); draw_range.start *= (canvas->pvt->width-2*canvas->pvt->margins); draw_range.end *= (canvas->pvt->width-2*canvas->pvt->margins); elem_start = draw_range.start + canvas->pvt->margins; elem_width = draw_range.end - draw_range.start; gt_assert(elem_start != GT_UNDEF_DOUBLE && elem_width != GT_UNDEF_DOUBLE); if (gt_element_is_marked(elem)) { if (gt_style_get_color_with_track(canvas->pvt->sty, type, "stroke_marked", &elem_color, gt_element_get_node_ref(elem), gt_track_get_title(canvas->pvt->current_track), err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num_with_track(canvas->pvt->sty, "format", "stroke_marked_width", &stroke_width, gt_element_get_node_ref(elem), gt_track_get_title(canvas->pvt->current_track), err) == GT_STYLE_QUERY_ERROR) { return -1; } } else { if (gt_style_get_color_with_track(canvas->pvt->sty, type, "stroke", &elem_color, gt_element_get_node_ref(elem), gt_track_get_title(canvas->pvt->current_track), err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num_with_track(canvas->pvt->sty, "format", "stroke_width", &stroke_width, gt_element_get_node_ref(elem), gt_track_get_title(canvas->pvt->current_track), err) == GT_STYLE_QUERY_ERROR) { return -1; } if (gt_style_get_num_with_track(canvas->pvt->sty, type, "stroke_width", &stroke_width, gt_element_get_node_ref(elem), gt_track_get_title(canvas->pvt->current_track), err) == GT_STYLE_QUERY_ERROR) { return -1; } } if (gt_style_get_color_with_track(canvas->pvt->sty, type, "fill", &fill_color, gt_element_get_node_ref(elem), gt_track_get_title(canvas->pvt->current_track), err) == GT_STYLE_QUERY_ERROR) { return -1; } if (canvas->pvt->bt && gt_double_smaller_double(draw_range.end-draw_range.start, 1.1)) { if ((unsigned long) draw_range.start > gt_bittab_size(canvas->pvt->bt)) return had_err; if (gt_bittab_bit_is_set(canvas->pvt->bt, (unsigned long) draw_range.start)) return had_err; gt_graphics_draw_vertical_line(canvas->pvt->g, elem_start, canvas->pvt->y - bar_height/2, elem_color, bar_height, stroke_width); gt_bittab_set_bit(canvas->pvt->bt, (unsigned long) draw_range.start); } /* register coordinates in GtImageInfo object if available */ if (canvas->pvt->ii) { GtRecMap *rm = gt_rec_map_new(elem_start, canvas->pvt->y - bar_height/2, elem_start+elem_width, canvas->pvt->y+bar_height/2, (GtFeatureNode*) gt_element_get_node_ref(elem)); gt_image_info_add_rec_map(canvas->pvt->ii, rm); } if (canvas->pvt->bt && draw_range.end-draw_range.start <= 1.1) { return had_err; } gt_log_log("drawing element from %f to %f, arrow status: %d", draw_range.start, draw_range.end, arrow_status); /* draw each element according to style set in the style */ style = gt_str_new(); rval = gt_style_get_str_with_track(canvas->pvt->sty, type, "style", style, gt_element_get_node_ref(elem), gt_track_get_title(canvas->pvt->current_track), err); switch (rval) { case GT_STYLE_QUERY_NOT_SET: gt_str_set(style, "box"); /* default style */ break; case GT_STYLE_QUERY_ERROR: gt_str_delete(style); gt_assert(gt_error_is_set(err)); return -1; default: break; } if (strcmp(gt_str_get(style), "box") == 0) { gt_graphics_draw_box(canvas->pvt->g, elem_start, canvas->pvt->y - bar_height/2, elem_width, bar_height, fill_color, arrow_status, arrow_width, stroke_width, elem_color, false); } else if (strcmp(gt_str_get(style), "rectangle") == 0) { gt_graphics_draw_box(canvas->pvt->g, elem_start, canvas->pvt->y - bar_height/2, elem_width, bar_height, fill_color, ARROW_NONE, arrow_width, stroke_width, elem_color, false); } else if (strcmp(gt_str_get(style), "caret") == 0) { gt_graphics_draw_caret(canvas->pvt->g, elem_start, canvas->pvt->y - bar_height/2, elem_width, bar_height, ARROW_NONE, arrow_width, stroke_width, elem_color); } else if (strcmp(gt_str_get(style), "dashes") == 0) { gt_graphics_draw_dashes(canvas->pvt->g, elem_start, canvas->pvt->y - bar_height/2, elem_width, bar_height, arrow_status, arrow_width, stroke_width, elem_color); } else if (strcmp(gt_str_get(style), "line") == 0) { gt_graphics_draw_horizontal_line(canvas->pvt->g, elem_start, canvas->pvt->y - bar_height/2, elem_color, elem_width, 1.0); } else { gt_graphics_draw_box(canvas->pvt->g, elem_start, canvas->pvt->y - bar_height/2, elem_width, bar_height, fill_color, arrow_status, arrow_width, stroke_width, elem_color, false); } gt_str_delete(style); /* draw arrowheads at clipped margins */ if (draw_range.clip == CLIPPED_LEFT || draw_range.clip == CLIPPED_BOTH) gt_graphics_draw_arrowhead(canvas->pvt->g, canvas->pvt->margins - 10, canvas->pvt->y - 4, grey, ARROW_LEFT); if (draw_range.clip == CLIPPED_RIGHT || draw_range.clip == CLIPPED_BOTH) gt_graphics_draw_arrowhead(canvas->pvt->g, canvas->pvt->width-canvas->pvt->margins + 10, canvas->pvt->y - 4, grey, ARROW_RIGHT); return had_err; }