/* File: zmapWindowCollectionFeature.c * Author: Roy Storey (rds@sanger.ac.uk) * Copyright (c) 2006-2010: Genome Research Ltd. *------------------------------------------------------------------- * ZMap is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt *------------------------------------------------------------------- * This file is part of the ZMap genome database package * originally written by: * * Ed Griffiths (Sanger Institute, UK) edgrif@sanger.ac.uk, * Roy Storey (Sanger Institute, UK) rds@sanger.ac.uk * * Description: * * Exported functions: See XXXXXXXXXXXXX.h * HISTORY: * Last edited: Apr 28 09:50 2010 (edgrif) * Created: Wed Dec 3 10:02:22 2008 (rds) * CVS info: $Id: zmapWindowCollectionFeature.c,v 1.26 2010-05-19 15:21:04 mh17 Exp $ *------------------------------------------------------------------- */ #include <math.h> #include <glib.h> #include <zmapWindowCollectionFeature_I.h> typedef enum {FIRST_MATCH, LAST_MATCH} MatchType ; typedef struct { ZMapWindowCanvasItem parent; FooCanvasGroup *new_parent; double x, y; } ParentPositionStruct, *ParentPosition; typedef struct { ZMapWindowCanvasItem parent; FooCanvasItem *previous; ZMapFeature prev_feature; GdkColor perfect; GdkColor colinear; GdkColor non_colinear; double x; ZMapFeatureCompareFunc compare_func; gpointer compare_data; } ColinearMarkerDataStruct, *ColinearMarkerData; static void zmap_window_collection_feature_class_init (ZMapWindowCollectionFeatureClass collection_class); static void zmap_window_collection_feature_init (ZMapWindowCollectionFeature group); static void zmap_window_collection_feature_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec); static void zmap_window_collection_feature_get_property(GObject *object, guint param_id, GValue *value, GParamSpec *pspec); static void zmap_window_collection_feature_destroy (GObject *object); static double zmap_window_collection_feature_item_point (FooCanvasItem *item, double x, double y, int cx, int cy, FooCanvasItem **actual_item); static FooCanvasItem *zmap_window_collection_feature_add_interval(ZMapWindowCanvasItem collection, ZMapFeatureSubPartSpan unused, double top, double bottom, double left, double right); static ZMapFeatureTypeStyle zmap_window_collection_feature_get_style(ZMapWindowCanvasItem canvas_item); static ZMapFeatureTypeStyle get_sub_feature_style(ZMapWindowCanvasItem canvas_item,GQuark id); /* Accessory functions, some from foo-canvas.c */ static double get_glyph_mid_point(FooCanvasItem *item); static void group_remove(gpointer data, gpointer user_data); static void add_colinear_lines(gpointer data, gpointer user_data); static void markMatchIfIncomplete(ZMapWindowCanvasItem collection, ZMapStrand ref_strand, MatchType match_type, FooCanvasItem *item, ZMapFeature feature) ; static gboolean fragments_splice(char *fragment_a, char *fragment_b); static void process_feature(ZMapFeature prev_feature); static ZMapWindowCanvasItemClass canvas_parent_class_G = NULL; static FooCanvasItemClass *item_parent_class_G = NULL; GType zMapWindowCollectionFeatureGetType(void) { static GType group_type = 0; if (!group_type) { static const GTypeInfo group_info = { sizeof (zmapWindowCollectionFeatureClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) zmap_window_collection_feature_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (zmapWindowCollectionFeature), 0, /* n_preallocs */ (GInstanceInitFunc) zmap_window_collection_feature_init }; group_type = g_type_register_static (zMapWindowCanvasItemGetType(), ZMAP_WINDOW_COLLECTION_FEATURE_NAME, &group_info, 0); } return group_type; } ZMapWindowCanvasItem zMapWindowCollectionFeatureCreate(FooCanvasGroup *parent) { ZMapWindowCanvasItem canvas_item = NULL; FooCanvasItem *item; //#define DEBUG_PINK_COLLECTION_FEATURE_BACKGROUND item = foo_canvas_item_new(parent, zMapWindowCollectionFeatureGetType(), "x", 0.0, "y", 0.0, NULL); if(item && ZMAP_IS_CANVAS_ITEM(item)) { #ifdef DEBUG_PINK_COLLECTION_FEATURE_BACKGROUND FooCanvasItem *background; #endif /* DEBUG_PINK_COLLECTION_FEATURE_BACKGROUND */ canvas_item = ZMAP_CANVAS_ITEM(item); if(ZMAP_CANVAS_ITEM_GET_CLASS(canvas_item)->post_create) (* ZMAP_CANVAS_ITEM_GET_CLASS(canvas_item)->post_create)(canvas_item); #ifdef DEBUG_PINK_COLLECTION_FEATURE_BACKGROUND if((background = canvas_item->items[WINDOW_ITEM_BACKGROUND])) { GdkColor fill = {0}; gdk_color_parse("pink", &fill); foo_canvas_item_set(background, "fill_color_gdk", &fill, NULL); } #endif zMapWindowCanvasItemCheckSize(canvas_item); } return canvas_item; } void zMapWindowCollectionFeatureRemoveSubFeatures(ZMapWindowCanvasItem collection, gboolean keep_in_place_x, gboolean keep_in_place_y) { ParentPositionStruct parent_data = {NULL}; FooCanvasItem *item; FooCanvasGroup *group; item = FOO_CANVAS_ITEM(collection); group = FOO_CANVAS_GROUP(item); parent_data.new_parent = FOO_CANVAS_GROUP(item->parent); parent_data.parent = collection; parent_data.x = parent_data.y = 0.0; if(keep_in_place_x) parent_data.x = group->xpos; if(keep_in_place_y) parent_data.y = group->ypos; g_list_foreach(group->item_list, group_remove, &parent_data); g_list_free(group->item_list); group->item_list = group->item_list_end = NULL; return ; } void zMapWindowCollectionFeatureStaticReparent(ZMapWindowCanvasItem reparentee, ZMapWindowCanvasItem new_parent) { FooCanvasItem *item; FooCanvasGroup *parent_group, *child_group; double x, y; parent_group = FOO_CANVAS_GROUP(new_parent); child_group = FOO_CANVAS_GROUP(reparentee); item = FOO_CANVAS_ITEM(reparentee); zMapWindowCanvasItemReparent(item, parent_group); x = child_group->xpos - parent_group->xpos; y = child_group->ypos - parent_group->ypos; foo_canvas_item_set(item, "x", x, "y", y, NULL); new_parent->feature = NULL;//reparentee->feature; return; } void zMapWindowCollectionFeatureAddColinearMarkers(ZMapWindowCanvasItem collection, ZMapFeatureCompareFunc compare_func, gpointer compare_data) { ColinearMarkerDataStruct colinear_data = {NULL}; FooCanvasGroup *group; group = FOO_CANVAS_GROUP(collection); colinear_data.parent = collection; if(group->item_list) { ZMapFeatureTypeStyle style; double x2; char *perfect_colour = ZMAP_WINDOW_MATCH_PERFECT ; char *colinear_colour = ZMAP_WINDOW_MATCH_COLINEAR ; char *noncolinear_colour = ZMAP_WINDOW_MATCH_NOTCOLINEAR ; colinear_data.previous = FOO_CANVAS_ITEM(group->item_list->data); colinear_data.prev_feature = ZMAP_CANVAS_ITEM(colinear_data.previous)->feature; colinear_data.compare_func = compare_func; colinear_data.compare_data = compare_data; style = (ZMAP_CANVAS_ITEM_GET_CLASS(colinear_data.previous)->get_style)(ZMAP_CANVAS_ITEM(colinear_data.previous)); x2 = zMapStyleGetWidth(style); colinear_data.x = (x2 * 0.5); gdk_color_parse(perfect_colour, &colinear_data.perfect) ; gdk_color_parse(colinear_colour, &colinear_data.colinear) ; gdk_color_parse(noncolinear_colour, &colinear_data.non_colinear) ; g_list_foreach(group->item_list->next, add_colinear_lines, &colinear_data); } return ; } void zMapWindowCollectionFeatureAddIncompleteMarkers(ZMapWindowCanvasItem collection, gboolean revcomped_features) { FooCanvasGroup *group; if ((group = FOO_CANVAS_GROUP(collection)) && (group->item_list)) { ZMapWindowCanvasItem canvas_item ; FooCanvasItem *first_item, *last_item ; ZMapFeature first_feature, last_feature ; ZMapStrand ref_strand ; /* Assume that match is forward so first match is first item, last match is last item. */ first_item = FOO_CANVAS_ITEM(group->item_list->data); canvas_item = ZMAP_CANVAS_ITEM(first_item); first_feature = canvas_item->feature; last_item = FOO_CANVAS_ITEM(group->item_list_end->data); canvas_item = ZMAP_CANVAS_ITEM(last_item); last_feature = canvas_item->feature; /* Now we have a feature we can retrieve which strand of the reference sequence the * alignment is to. */ ref_strand = first_feature->strand ; /* If the alignment is to the reverse strand of the reference sequence then swop first and last. */ if (ref_strand == ZMAPSTRAND_REVERSE) { last_item = FOO_CANVAS_ITEM(group->item_list->data); canvas_item = ZMAP_CANVAS_ITEM(last_item); last_feature = canvas_item->feature; first_item = FOO_CANVAS_ITEM(group->item_list_end->data); canvas_item = ZMAP_CANVAS_ITEM(first_item); first_feature = canvas_item->feature; } /* If either the first or last match features are truncated then add the incomplete marker. */ markMatchIfIncomplete(collection, ref_strand, FIRST_MATCH, first_item, first_feature) ; markMatchIfIncomplete(collection, ref_strand, LAST_MATCH, last_item, last_feature) ; } return ; } void zMapWindowCollectionFeatureAddSpliceMarkers(ZMapWindowCanvasItem collection) { FooCanvasGroup *group; double x_coord; gboolean canonical ; ZMapFeatureTypeStyle style; group = FOO_CANVAS_GROUP(collection); canonical = FALSE ; if(group->item_list && group->item_list->next) { GList *list; ZMapFeature prev_feature; ZMapFeature curr_feature; if((prev_feature = zMapWindowCanvasItemGetFeature(group->item_list->data))) process_feature(prev_feature); if((list = group->item_list->next)) x_coord = get_glyph_mid_point(list->data); while(list && prev_feature) { char *prev, *curr; gboolean prev_reversed, curr_reversed; curr_feature = zMapWindowCanvasItemGetFeature(list->data); prev_reversed = prev_feature->strand == ZMAPSTRAND_REVERSE; curr_reversed = curr_feature->strand == ZMAPSTRAND_REVERSE; process_feature(curr_feature); prev = zMapFeatureGetDNA((ZMapFeatureAny)prev_feature, prev_feature->x2 + 1, prev_feature->x2 + 2, prev_reversed); curr = zMapFeatureGetDNA((ZMapFeatureAny)curr_feature, curr_feature->x1 - 2, curr_feature->x1 - 1, curr_reversed); if(prev && curr && fragments_splice(prev, curr)) { FooCanvasGroup *parent; GQuark id; parent = FOO_CANVAS_GROUP(collection->items[WINDOW_ITEM_OVERLAY]); style = (ZMAP_CANVAS_ITEM_GET_CLASS(collection)->get_style)(collection); if(style && (id = zMapStyleGetSubFeature(style,ZMAPSTYLE_SUB_FEATURE_NON_CONCENCUS_SPLICE))) { style = get_sub_feature_style(collection,id); if(style) { zMapWindowGlyphItemCreate(parent,style,3, x_coord,prev_feature->x2 - group->ypos,0, FALSE); zMapWindowGlyphItemCreate(parent,style,5, x_coord,curr_feature->x1 - group->ypos - 1,0 ,FALSE); } } } /* free */ if(prev) g_free(prev); if(curr) g_free(curr); /* move on. */ prev_feature = curr_feature; list = list->next; } } return ; } /* * Internal routines. */ static FooCanvasItem *zmap_window_collection_feature_add_interval(ZMapWindowCanvasItem collection, ZMapFeatureSubPartSpan unused, double top, double bottom, double left, double right) { FooCanvasItem *item = NULL; /* these will be the joining bits */ return item; } static void zmap_window_collection_feature_set_colour(ZMapWindowCanvasItem canvas_item, FooCanvasItem *interval, ZMapFeatureSubPartSpan sub_feature, ZMapStyleColourType colour_type, GdkColor *default_fill) { if(ZMAP_IS_CANVAS_ITEM(interval)) { if(ZMAP_CANVAS_ITEM_GET_CLASS(interval)->set_colour) (ZMAP_CANVAS_ITEM_GET_CLASS(interval)->set_colour)(canvas_item, interval, sub_feature, colour_type, default_fill); } else { /* chain up? Actually I think we need to do something else... */ if(canvas_parent_class_G->set_colour) (canvas_parent_class_G->set_colour)(canvas_item, interval, sub_feature, colour_type, default_fill); } return ; } static ZMapFeatureTypeStyle zmap_window_collection_feature_get_style(ZMapWindowCanvasItem canvas_item) { ZMapFeatureTypeStyle style = NULL; ZMapWindowContainerGroup container_parent; FooCanvasItem *item; FooCanvasGroup *group; g_return_val_if_fail(canvas_item != NULL, NULL); item = FOO_CANVAS_ITEM(canvas_item); group = FOO_CANVAS_GROUP(canvas_item); if(item->parent && item->parent->parent && group->item_list) { ZMapWindowCanvasItem first_item; first_item = ZMAP_CANVAS_ITEM(group->item_list->data); container_parent = zmapWindowContainerCanvasItemGetContainer(item); /* can optimise this a bit, by including the featureset_i header... */ style = zmapWindowContainerFeatureSetStyleFromID((ZMapWindowContainerFeatureSet)container_parent, first_item->feature->style_id); } return style; } // our style references others, which will be in the container's hash table // this needs to go somewhere else: maybe CanvasItem.c? static ZMapFeatureTypeStyle get_sub_feature_style(ZMapWindowCanvasItem canvas_item,GQuark id) { ZMapFeatureTypeStyle sub_style = NULL; ZMapWindowContainerGroup container_parent; FooCanvasItem *item; FooCanvasGroup *group; g_return_val_if_fail(canvas_item != NULL, NULL); item = FOO_CANVAS_ITEM(canvas_item); group = FOO_CANVAS_GROUP(canvas_item); if(item->parent && item->parent->parent && group->item_list) { container_parent = zmapWindowContainerCanvasItemGetContainer(item); sub_style = zmapWindowContainerFeatureSetStyleFromID((ZMapWindowContainerFeatureSet)container_parent, id); } return sub_style; } /* object impl */ static void zmap_window_collection_feature_class_init (ZMapWindowCollectionFeatureClass collection_class) { ZMapWindowCanvasItemClass canvas_class; FooCanvasItemClass *item_class; GObjectClass *gobject_class; gobject_class = (GObjectClass *) collection_class; canvas_class = (ZMapWindowCanvasItemClass)collection_class; item_class = (FooCanvasItemClass *)collection_class; gobject_class->set_property = zmap_window_collection_feature_set_property; gobject_class->get_property = zmap_window_collection_feature_get_property; // g_object_class_override_property(gobject_class, COLLECTION_INTERVAL_TYPE, // ZMAP_WINDOW_CANVAS_INTERVAL_TYPE); item_class->point = zmap_window_collection_feature_item_point; item_parent_class_G = g_type_class_peek (foo_canvas_group_get_type()); canvas_parent_class_G = g_type_class_peek(zMapWindowCanvasItemGetType()); item_class->bounds = item_parent_class_G->bounds; canvas_class->add_interval = zmap_window_collection_feature_add_interval; canvas_class->set_colour = zmap_window_collection_feature_set_colour; canvas_class->check_data = NULL; canvas_class->get_style = zmap_window_collection_feature_get_style; gobject_class->dispose = zmap_window_collection_feature_destroy; return ; } static void zmap_window_collection_feature_init (ZMapWindowCollectionFeature collection) { ZMapWindowCanvasItem canvas_item; canvas_item = ZMAP_CANVAS_ITEM(collection); canvas_item->auto_resize_background = TRUE; return ; } static void zmap_window_collection_feature_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { ZMapWindowCanvasItem canvas_item; ZMapWindowCollectionFeature collection; g_return_if_fail(ZMAP_IS_WINDOW_COLLECTION_FEATURE(object)); collection = ZMAP_WINDOW_COLLECTION_FEATURE(object); canvas_item = ZMAP_CANVAS_ITEM(object); switch(param_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); break; } return ; } static void zmap_window_collection_feature_get_property(GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { return ; } static double window_collection_feature_invoke_point (FooCanvasItem *item, double x, double y, int cx, int cy, FooCanvasItem **actual_item) { /* Calculate x & y in item local coordinates */ if (FOO_CANVAS_ITEM_GET_CLASS (item)->point) return FOO_CANVAS_ITEM_GET_CLASS (item)->point (item, x, y, cx, cy, actual_item); return 1e18; } /* Point handler for canvas groups */ static double zmap_window_collection_feature_item_point (FooCanvasItem *item, double x, double y, int cx, int cy, FooCanvasItem **actual_item) { FooCanvasGroup *group; FooCanvasItem *child, *point_item; GList *list = NULL; int x1, y1, x2, y2; double gx, gy; double dist, best; group = FOO_CANVAS_GROUP (item); x1 = cx - item->canvas->close_enough; y1 = cy - item->canvas->close_enough; x2 = cx + item->canvas->close_enough; y2 = cy + item->canvas->close_enough; best = 0.0; *actual_item = NULL; gx = x - group->xpos; gy = y - group->ypos; dist = 0.0; /* keep gcc happy */ list = group->item_list; while(list) { child = list->data; if ((child->object.flags & FOO_CANVAS_ITEM_MAPPED) && FOO_CANVAS_ITEM_GET_CLASS (child)->point) { dist = window_collection_feature_invoke_point (child, gx, gy, cx, cy, &point_item); if(point_item && ((int)(dist * item->canvas->pixels_per_unit_x + 0.5) <= item->canvas->close_enough) && (dist <= best)) { best = dist; *actual_item = point_item; } } list = list->next; } if(actual_item == NULL && item_parent_class_G->point) best = (item_parent_class_G->point)(item, x, y, cx, cy, actual_item); return best; } static void zmap_window_collection_feature_destroy (GObject *object) { GObjectClass *object_class; zMapWindowCollectionFeatureRemoveSubFeatures(ZMAP_CANVAS_ITEM(object), TRUE, TRUE); object_class = (GObjectClass *)canvas_parent_class_G; if(object_class->dispose) (object_class->dispose)(object); return ; } /* Accessory functions, some copied as they were statics in foo-canvas.c */ static double get_glyph_mid_point(FooCanvasItem *item) { double x, x1, x2, y1, y2; foo_canvas_item_get_bounds(item, &x1, &y1, &x2, &y2); /* centre point - half width + rounding */ x = (((x2 - x1) * 0.5) + x1) + 0.5; return x; } static void group_remove(gpointer data, gpointer user_data) { FooCanvasItem *item2remove = FOO_CANVAS_ITEM(data); ParentPosition parent_data = (ParentPosition)user_data; double x, y; if(ZMAP_IS_CANVAS_ITEM(data)) { g_object_get(G_OBJECT(item2remove), "x", &x, "y", &y, NULL); zMapWindowCanvasItemReparent(item2remove, parent_data->new_parent); x += parent_data->x; y += parent_data->y; foo_canvas_item_set(item2remove, "x", x, "y", y, NULL); } return ; } static void add_colinear_lines(gpointer data, gpointer user_data) { ColinearMarkerData colinear_data = (ColinearMarkerData)user_data; ZMapWindowCanvasItem canvas_item = NULL; FooCanvasItem *current = FOO_CANVAS_ITEM(data); FooCanvasItem *previous; ZMapFeature prev_feature, curr_feature; GdkColor *draw_colour; FooCanvasPoints line_points; double coords[4], y1, y2; ColinearityType colinearity = 0; // enum {COLINEAR_INVALID, COLINEAR_NOT, COLINEAR_IMPERFECT, COLINEAR_PERFECT}; // defined in zmapWindow_P.h previous = colinear_data->previous; colinear_data->previous = current; prev_feature = colinear_data->prev_feature; curr_feature = ZMAP_CANVAS_ITEM(current)->feature; colinear_data->prev_feature = curr_feature; canvas_item = ZMAP_CANVAS_ITEM(colinear_data->parent); if(colinear_data->compare_func) { colinearity = (colinear_data->compare_func)(prev_feature, curr_feature, colinear_data->compare_data); if(colinearity != COLINEAR_INVALID) { FooCanvasGroup *canvas_group; FooCanvasItem *colinear_line; double py1, py2, cy1, cy2; if (colinearity == COLINEAR_NOT) draw_colour = &colinear_data->non_colinear ; else if (colinearity == COLINEAR_IMPERFECT) draw_colour = &colinear_data->colinear ; else draw_colour = &colinear_data->perfect ; foo_canvas_item_get_bounds(previous, NULL, &py1, NULL, &py2); foo_canvas_item_get_bounds(current, NULL, &cy1, NULL, &cy2); canvas_group = (FooCanvasGroup *)canvas_item; y1 = floor(py2); y2 = ceil (cy1); y1 = prev_feature->x2 - canvas_group->ypos; y2 = curr_feature->x1 - canvas_group->ypos - 1.0; /* Ext2Zero */ coords[0] = colinear_data->x; coords[1] = y1; coords[2] = colinear_data->x; coords[3] = y2; line_points.coords = coords; line_points.num_points = 2; line_points.ref_count = 1; colinear_line = foo_canvas_item_new(FOO_CANVAS_GROUP(canvas_item->items[WINDOW_ITEM_UNDERLAY]), foo_canvas_line_get_type(), "width_pixels", 1, "points", &line_points, "fill_color_gdk", draw_colour, NULL); // canvas_item->debug = 1; /* mh17: not sure if this is valid/safe.. * can't find any definition anywhere of what map and realize signify, * can only see that they set the MAPPED and REALIZED flags * However, this causes the underlay and overlay features to draw as required. * Q: would CollectionFeature be better coded as another layer of CanvasItemGroup? * then we'd only have one lot of code to debug */ // see also gylphs // these don't work! if(!(colinear_line->object.flags & FOO_CANVAS_ITEM_REALIZED)) FOO_CANVAS_ITEM_GET_CLASS(colinear_line)->realize (colinear_line); if(!(colinear_line->object.flags & FOO_CANVAS_ITEM_MAPPED)) FOO_CANVAS_ITEM_GET_CLASS(colinear_line)->map (colinear_line); zmapWindowLongItemCheckPointFull(colinear_line, &line_points, 0.0, 0.0, 0.0, 0.0); } } return ; } /* Mark a first or last feature in a series of alignment features as incomplete. * The first feature is incomplete if it's start > 1, the last is incomplete * if it's end < homol_length. * * Code is complicated by markers/coord testing needing to be reversed for * alignments to reverse strand. */ static void markMatchIfIncomplete(ZMapWindowCanvasItem collection, ZMapStrand ref_strand, MatchType match_type, FooCanvasItem *item, ZMapFeature feature) { int start, end ; if (match_type == FIRST_MATCH) { start = 1 ; end = feature->feature.homol.y1 ; } else { start = feature->feature.homol.y2 ; end = feature->feature.homol.length ; } if (start < end) { double x_coord, y_coord ; int diff; ZMapFeatureTypeStyle style, sub_style = NULL; FooCanvasItem *foo; GQuark id; gboolean rev_strand = FALSE; if(feature->strand == ZMAPSTRAND_REVERSE) rev_strand = TRUE;; style = (ZMAP_CANVAS_ITEM_GET_CLASS(collection)->get_style)(collection) ; // if homology is configured and we have the style... if(style && (id = zMapStyleGetSubFeature(style,ZMAPSTYLE_SUB_FEATURE_HOMOLOGY))) sub_style = get_sub_feature_style(collection,id); // otherwise (eg style from ACEDB) if legacy switched on then invent it if(!sub_style) sub_style = zMapStyleLegacyStyle((char *) zmapStyleSubFeature2ExactStr(ZMAPSTYLE_SUB_FEATURE_HOMOLOGY)); if(sub_style) { x_coord = get_glyph_mid_point(item) ; if ((match_type == FIRST_MATCH && ref_strand == ZMAPSTRAND_FORWARD) || (match_type == LAST_MATCH && ref_strand == ZMAPSTRAND_REVERSE)) { y_coord = feature->x1 - ((FooCanvasGroup *)collection)->ypos - 1.0 ; /* Ext2Zero */ } else { y_coord = feature->x2 - ((FooCanvasGroup *)collection)->ypos; } diff = end - start; foo = FOO_CANVAS_ITEM(zMapWindowGlyphItemCreate(FOO_CANVAS_GROUP(collection->items[WINDOW_ITEM_OVERLAY]), sub_style, (match_type == FIRST_MATCH) ? 5 : 3, x_coord,y_coord,diff, rev_strand)); /* mh17: not sure if this is valid/safe..we're not using the layers that have been set up so carefully * can't find any definition anywhere of what map and realize signify, * can only see that they set the MAPPED and REALIZED flags * However, this causes the underlay and overlay features to draw as required. * Q: would CollectionFeature be better coded as another layer of CanvasItemGroup? * then we'd only have one lot of code to debug */ // see also colinear lines // these don't work! if(foo) { if(!(foo->object.flags & FOO_CANVAS_ITEM_REALIZED)) FOO_CANVAS_ITEM_GET_CLASS(foo)->realize (foo); if(!(foo->object.flags & FOO_CANVAS_ITEM_MAPPED)) FOO_CANVAS_ITEM_GET_CLASS(foo)->map (foo); } } } return ; } static gboolean fragments_splice(char *fragment_a, char *fragment_b) { gboolean splice = FALSE; char spliceosome[5]; if(fragment_a == NULL || fragment_b == NULL) { splice = FALSE; } else { spliceosome[0] = fragment_a[0]; spliceosome[1] = fragment_a[1]; spliceosome[2] = fragment_b[0]; spliceosome[3] = fragment_b[1]; spliceosome[4] = '\0'; if(g_ascii_strcasecmp(&spliceosome[0], "GTAG") == 0) { splice = TRUE; } else if(g_ascii_strcasecmp(&spliceosome[0], "GCAG") == 0) { splice = TRUE; } else if(g_ascii_strcasecmp(&spliceosome[0], "ATAC") == 0) { splice = TRUE; } } #ifdef ED_G_NEVER_INCLUDE_THIS_CODE if(splice) { // printf("splices: %s\n", &spliceosome[0]); } #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ return splice; } static void process_feature(ZMapFeature prev_feature) { int i; gboolean reversed; reversed = prev_feature->strand == ZMAPSTRAND_REVERSE; if(prev_feature->feature.homol.align && prev_feature->feature.homol.align->len > 1) { ZMapAlignBlock prev_align, curr_align; prev_align = &(g_array_index(prev_feature->feature.homol.align, ZMapAlignBlockStruct, 0));; for(i = 1; i < prev_feature->feature.homol.align->len; i++) { char *prev, *curr; curr_align = &(g_array_index(prev_feature->feature.homol.align, ZMapAlignBlockStruct, i)); if(prev_align->t2 + 4 < curr_align->t1) { prev = zMapFeatureGetDNA((ZMapFeatureAny)prev_feature, prev_align->t2 + 1, prev_align->t2 + 2, reversed); curr = zMapFeatureGetDNA((ZMapFeatureAny)prev_feature, curr_align->t1 - 2, curr_align->t1 - 1, reversed); if(prev && curr) fragments_splice(prev, curr); if(prev) g_free(prev); if(curr) g_free(curr); } prev_align = curr_align; } } return ; }