Ejemplo n.º 1
0
void gt_string_matching_shift_and(const char *s, unsigned long n,
                               const char *p, unsigned long m,
                               ProcessMatch process_match, void *data)
{
  GtBittab *D, *B[UCHAR_MAX] = { NULL };
  unsigned long i, j;
  gt_assert(s && p);
  if (m > n || !m || !n) /* no match possible */
    return;
  /* preprocessing */
  for (j = 0; j < m; j++) {
    if (!B[(unsigned) p[j]])
      B[(unsigned) p[j]] = gt_bittab_new(m);
    gt_bittab_set_bit(B[(unsigned) p[j]], j);
  }
  /* searching */
  D = gt_bittab_new(m);
  for (i = 0; i < n; i++) {
    gt_bittab_shift_left_equal(D);
    gt_bittab_set_bit(D, 0);
    if (B[(unsigned) s[i]])
      gt_bittab_and_equal(D, B[(unsigned) s[i]]);
    else
      gt_bittab_unset(D);
    if (gt_bittab_bit_is_set(D, m - 1) && process_match) {
      if (process_match(i - m + 1, data))
        break;
    }
  }
  /* free */
  for (i = 0; i < UCHAR_MAX; i++)
    gt_bittab_delete(B[i]);
  gt_bittab_delete(D);
}
Ejemplo n.º 2
0
GtBittab* gt_golomb_encode(GtGolomb *golomb, unsigned long x)
{
  unsigned long quotient,
                remain,
                mask,
                idx_i;
  GtBittab *code;
  gt_assert(golomb);

  quotient = x / golomb->median;
  remain = x - quotient * golomb->median;

  if (golomb->len == 0) {
    code = gt_bittab_new((quotient + 1) + 1);
  }
  else if (remain < golomb->two_pow_len - golomb->median) {
    code = gt_bittab_new((quotient + 1) + (golomb->len - 1));

    mask = 1UL << (golomb->len - 2);
    for (idx_i = 0; idx_i < golomb->len - 1; idx_i++) {
      if (remain & mask)
        gt_bittab_set_bit(code, quotient + 1 + idx_i);
      mask >>= 1;
    }
  }
Ejemplo n.º 3
0
/* necessary to call consensus_sa() */
static void process_splice_form_func(GtArray *spliced_alignments_in_form,
                                     GT_UNUSED const void *set_of_sas,
                                     GT_UNUSED GtUword number_of_sas,
                                     GT_UNUSED size_t size_of_sa,
                                     void *userdata)
{
  GthPGL *pgl = (GthPGL*) userdata;
  GthAGS *ags;
  GtBittab *assemblytab;
  GtUword i;

  ags = gth_ags_new(pgl);

  assemblytab = gt_bittab_new(gt_array_size(pgl->saclusters));
  for (i = 0; i < gt_array_size(spliced_alignments_in_form); i++) {
    gt_bittab_set_bit(assemblytab, *(GtUword*)
                                gt_array_get(spliced_alignments_in_form, i));
  }

  gth_build_AGS_from_assembly(ags, assemblytab, pgl->saclusters);

  gt_bittab_delete(assemblytab);

  gt_array_add(pgl->assemblies, ags);
}
Ejemplo n.º 4
0
static void compute_C(GtBittab **C, const ConsensusSA *csa)
{
  unsigned long sa, sa_1;
  gt_assert(csa);
  for (sa = 0; sa < csa->number_of_sas; sa++) {
    for (sa_1 = 0; sa_1 < csa->number_of_sas; sa_1++) {
      if (contains(csa, sa, sa_1))
        gt_bittab_set_bit(C[sa], sa_1);
    }
    gt_assert(gt_bittab_bit_is_set(C[sa], sa));
  }
}
Ejemplo n.º 5
0
static void compute_left_or_right(GtBittab **left_or_right,
                                  const ConsensusSA *csa,
                                  bool (*cmp_func) (const ConsensusSA *csa,
                                                    unsigned long sa_1,
                                                    unsigned long sa_2))
{
  unsigned long sa, sa_1;
  gt_assert(csa && left_or_right && *left_or_right);
  for (sa = 0; sa < csa->number_of_sas; sa++) {
    for (sa_1 = 0; sa_1 < csa->number_of_sas; sa_1++) {
      if (cmp_func(csa, sa, sa_1) && compatible(csa, sa, sa_1))
        gt_bittab_set_bit(left_or_right[sa], sa_1);
    }
  }
}
static int read_field_header_bittab(DescField *field,
                                    FILE *fp, GtError *err)
{
  int had_err = 0;
  char cc;
  GtUword char_idx,
          num_of_chars = field->len / sizeof (char);
  size_t bit_idx;

  if (field->len % sizeof (char) != 0)
    num_of_chars++;

  for (char_idx = 0; char_idx < num_of_chars; char_idx++) {
    had_err = gt_io_error_fread_one(cc, fp, err);
    for (bit_idx = 0; !had_err && bit_idx < sizeof (char); bit_idx++) {
      if (cc & (1 << bit_idx))
        gt_bittab_set_bit(field->bittab,
                          (GtUword) ((sizeof (char) * char_idx) +
                                     bit_idx));
    }
  }
  return had_err;
}
Ejemplo n.º 7
0
int gt_clustered_set_union_find_merge_clusters(GtClusteredSet *cs,
                                               GtUword e1,
                                               GtUword e2,
                                               GtError *err)
{
  gt_assert(cs);
  int had_err = 0;
  GtClusteredSetUFClusterInfo *cluster_info_c1 = NULL;
  GtClusteredSetUFClusterInfo *cluster_info_c2 = NULL;
  GtUword target = 0, source = 0, c1 = 0, c2 = 0;
  GtClusteredSetUF *cs_uf = (GtClusteredSetUF*) cs;
  if (e1 == e2) {
    gt_error_set(err, "expected "GT_WU" to be unequal "GT_WU"", e1, e2 );
    had_err = -1;
  }

  if (e1 >= cs_uf->num_of_elems || e2 >= cs_uf->num_of_elems) {
    gt_error_set(err, ""GT_WU" and "GT_WU" must not be larger than "GT_WU"",
                 e1, e2, cs_uf->num_of_elems);
    had_err = -1;
  }

  if (!had_err) {
    if (SINGLETON(e1)) {
       /* printf(""GT_WU" is singleton\n", e1); */
      if (SINGLETON(e2)) {
        /* printf(""GT_WU" is singleton\n", e2);*/
        gt_clustered_set_union_find_make_new_cluster(cs_uf, e1, e2, err);
        gt_bittab_set_bit(cs_uf->in_cluster, e2);
      }
      else {
        c2 = cs_uf->cluster_elems[e2].cluster_num;
        CHECKCLUSTER(c2);
        gt_clustered_set_union_find_append_elem(cs_uf, c2, e1, err);
      }
      gt_bittab_set_bit(cs_uf->in_cluster, e1);
    }
    else {
      c1 = cs_uf->cluster_elems[e1].cluster_num;
      CHECKCLUSTER(c1);
      if (SINGLETON(e2)) {
        gt_clustered_set_union_find_append_elem(cs_uf, c1, e2, err);
        gt_bittab_set_bit(cs_uf->in_cluster, e2);
      }
      else {
        c2 = cs_uf->cluster_elems[e2].cluster_num;
        CHECKCLUSTER(c2);
        cluster_info_c1 = CINFO(c1);
        cluster_info_c2 = CINFO(c2);
        if (cluster_info_c1->cluster_size > cluster_info_c2->cluster_size) {
          target = c1;
          source = c2;
        }
        else {
          target = c1;
          source = c2;
        }
        if (target != source)
          gt_clustered_set_union_find_join_clusters(cs_uf, target, source, err);
      }
    }
  }
  return had_err;
}
Ejemplo n.º 8
0
static void compute_csas(ConsensusSA *csa)
{
  unsigned long i, sa_i, sa_i_size = 0, sa_prime, sa_prime_size;
  GtArray *splice_form;
  GtBittab **C, **left, **right, **L, **R, *U_i, *SA_i, *SA_prime;
#ifndef NDEBUG
  unsigned long u_i_size, u_i_minus_1_size;
  gt_assert(csa && csa->set_of_sas);
#endif

  /* init sets */
  C     = gt_malloc(sizeof (GtBittab*) * csa->number_of_sas);
  left  = gt_malloc(sizeof (GtBittab*) * csa->number_of_sas);
  right = gt_malloc(sizeof (GtBittab*) * csa->number_of_sas);
  L     = gt_malloc(sizeof (GtBittab*) * csa->number_of_sas);
  R     = gt_malloc(sizeof (GtBittab*) * csa->number_of_sas);

  for (i = 0; i < csa->number_of_sas; i++) {
    C[i]     = gt_bittab_new(csa->number_of_sas);
    left[i]  = gt_bittab_new(csa->number_of_sas);
    right[i] = gt_bittab_new(csa->number_of_sas);
    L[i]     = gt_bittab_new(csa->number_of_sas);
    R[i]     = gt_bittab_new(csa->number_of_sas);
  }

  U_i      = gt_bittab_new(csa->number_of_sas);
  SA_i     = gt_bittab_new(csa->number_of_sas);
  SA_prime = gt_bittab_new(csa->number_of_sas);

  splice_form = gt_array_new(sizeof (unsigned long));

  /* compute sets */
  compute_C(C, csa);
  compute_left(left, csa);
  compute_right(right, csa);
  compute_L(L, C, left, csa->number_of_sas);
  compute_R(R, C, right, csa->number_of_sas);

  /* U_0 = SA */
  for (i = 0; i < csa->number_of_sas; i++)
    gt_bittab_set_bit(U_i, i);

#ifndef NDEBUG
  /* preparation for assertion below */
  u_i_minus_1_size = gt_bittab_count_set_bits(U_i);
#endif
  while (gt_bittab_is_true(U_i)) {
    sa_i = GT_UNDEF_ULONG;
    for (sa_prime  = gt_bittab_get_first_bitnum(U_i);
         sa_prime != gt_bittab_get_last_bitnum(U_i);
         sa_prime  = gt_bittab_get_next_bitnum(U_i, sa_prime)) {
      if (sa_i == GT_UNDEF_ULONG) {
        sa_i = sa_prime;
        gt_bittab_or(SA_i, L[sa_i], R[sa_i]);
        sa_i_size = gt_bittab_count_set_bits(SA_i);
      }
      else {
        gt_bittab_or(SA_prime, L[sa_prime], R[sa_prime]);
        sa_prime_size = gt_bittab_count_set_bits(SA_prime);
        if (sa_prime_size > sa_i_size) {
          sa_i = sa_prime;
          sa_i_size = sa_prime_size;
          gt_bittab_equal(SA_i, SA_prime);
        }
      }
    }

    /* make sure the computed splice form is maximal w.r.t. to compatibility */
    gt_assert(splice_form_is_valid(SA_i, csa));

    /* process splice form */
    if (csa->process_splice_form) {
      gt_array_reset(splice_form);
      gt_bittab_get_all_bitnums(SA_i, splice_form);
      csa->process_splice_form(splice_form, csa->set_of_sas, csa->number_of_sas,
                               csa->size_of_sa, csa->userdata);
    }

    /* U_i = U_i-1 \ SA_i */
    gt_bittab_nand(U_i, U_i, SA_i);

#ifndef NDEBUG
    /* ensure that |U_i| < |U_i-1| */
    u_i_size = gt_bittab_count_set_bits(U_i);
    gt_assert(u_i_size < u_i_minus_1_size);
    u_i_minus_1_size = u_i_size;
#endif
  }

  /* free sets */
  for (i = 0; i < csa->number_of_sas; i++) {
    gt_bittab_delete(C[i]);
    gt_bittab_delete(left[i]);
    gt_bittab_delete(right[i]);
    gt_bittab_delete(L[i]);
    gt_bittab_delete(R[i]);
  }
  gt_free(C);
  gt_free(left);
  gt_free(right);
  gt_free(L);
  gt_free(R);
  gt_bittab_delete(U_i);
  gt_bittab_delete(SA_i);
  gt_bittab_delete(SA_prime);
  gt_array_delete(splice_form);
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
0
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;
}