Skip to content
Snippets Groups Projects
zmapWindowCollectionFeature.c 28.2 KiB
Newer Older
/*  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.
mh17's avatar
mh17 committed
 *
 * 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.
mh17's avatar
mh17 committed
 *
 * 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
 *
mh17's avatar
mh17 committed
 * Description:
 *
 * Exported functions: See XXXXXXXXXXXXX.h
 * HISTORY:
edgrif's avatar
edgrif committed
 * 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 $
 *-------------------------------------------------------------------
 */
rds's avatar
rds committed
#include <math.h>
#include <zmapWindowCollectionFeature_I.h>
typedef enum {FIRST_MATCH, LAST_MATCH} MatchType ;

rds's avatar
rds committed
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);
mh17's avatar
mh17 committed
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);

rds's avatar
rds committed
static FooCanvasItem *zmap_window_collection_feature_add_interval(ZMapWindowCanvasItem   collection,
								  ZMapFeatureSubPartSpan unused,
								  double top,  double bottom,
								  double left, double right);
rds's avatar
rds committed
static ZMapFeatureTypeStyle zmap_window_collection_feature_get_style(ZMapWindowCanvasItem canvas_item);

static ZMapFeatureTypeStyle get_sub_feature_style(ZMapWindowCanvasItem canvas_item,GQuark id);
rds's avatar
rds committed
/* Accessory functions, some from foo-canvas.c */
static double get_glyph_mid_point(FooCanvasItem *item);
rds's avatar
rds committed
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) ;
rds's avatar
rds committed
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;
mh17's avatar
mh17 committed

  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
mh17's avatar
mh17 committed


mh17's avatar
mh17 committed

    group_type = g_type_register_static (zMapWindowCanvasItemGetType(),
					 ZMAP_WINDOW_COLLECTION_FEATURE_NAME,
					 &group_info,
					 0);
  }
mh17's avatar
mh17 committed

  return group_type;
}

ZMapWindowCanvasItem zMapWindowCollectionFeatureCreate(FooCanvasGroup *parent)
{
  ZMapWindowCanvasItem canvas_item = NULL;
  FooCanvasItem *item;

  //#define DEBUG_PINK_COLLECTION_FEATURE_BACKGROUND
mh17's avatar
mh17 committed
  item = foo_canvas_item_new(parent, zMapWindowCollectionFeatureGetType(),
			     "x", 0.0,
			     "y", 0.0,
mh17's avatar
mh17 committed

  if(item && ZMAP_IS_CANVAS_ITEM(item))
    {
#ifdef DEBUG_PINK_COLLECTION_FEATURE_BACKGROUND
rds's avatar
rds committed
      FooCanvasItem *background;
#endif /* DEBUG_PINK_COLLECTION_FEATURE_BACKGROUND */

      canvas_item = ZMAP_CANVAS_ITEM(item);
mh17's avatar
mh17 committed

      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
rds's avatar
rds committed
      if((background = canvas_item->items[WINDOW_ITEM_BACKGROUND]))
	{
	  GdkColor fill = {0};
mh17's avatar
mh17 committed

rds's avatar
rds committed
	  gdk_color_parse("pink", &fill);
rds's avatar
rds committed
	  foo_canvas_item_set(background, "fill_color_gdk", &fill, NULL);
	}
mh17's avatar
mh17 committed
      zMapWindowCanvasItemCheckSize(canvas_item);
mh17's avatar
mh17 committed

rds's avatar
rds committed
  return canvas_item;
mh17's avatar
mh17 committed
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 ;
}

mh17's avatar
mh17 committed
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;

mh17's avatar
mh17 committed
  foo_canvas_item_set(item,
rds's avatar
rds committed
  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)
    {
rds's avatar
rds committed
      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;

rds's avatar
rds committed
      style = (ZMAP_CANVAS_ITEM_GET_CLASS(colinear_data.previous)->get_style)(ZMAP_CANVAS_ITEM(colinear_data.previous));
rds's avatar
rds committed

      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) ;
mh17's avatar
mh17 committed

rds's avatar
rds committed

void zMapWindowCollectionFeatureAddSpliceMarkers(ZMapWindowCanvasItem collection)
rds's avatar
rds committed
  FooCanvasGroup *group;
rds's avatar
rds committed
  double x_coord;
  gboolean canonical ;

  group = FOO_CANVAS_GROUP(collection);

  canonical = FALSE ;
mh17's avatar
mh17 committed

  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);

rds's avatar
rds committed
      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;
mh17's avatar
mh17 committed

	  curr_feature = zMapWindowCanvasItemGetFeature(list->data);
mh17's avatar
mh17 committed

	  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;
	}
mh17's avatar
mh17 committed

mh17's avatar
mh17 committed
/*
rds's avatar
rds committed
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;
}

rds's avatar
rds committed
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 ;
}

rds's avatar
rds committed
static ZMapFeatureTypeStyle zmap_window_collection_feature_get_style(ZMapWindowCanvasItem canvas_item)
{
  ZMapFeatureTypeStyle style = NULL;
rds's avatar
rds committed
  ZMapWindowContainerGroup container_parent;
rds's avatar
rds committed
  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);

rds's avatar
rds committed
      container_parent = zmapWindowContainerCanvasItemGetContainer(item);

rds's avatar
rds committed
      /* can optimise this a bit, by including the featureset_i header... */
rds's avatar
rds committed
      style = zmapWindowContainerFeatureSetStyleFromID((ZMapWindowContainerFeatureSet)container_parent,
                                           first_item->feature->style_id);
rds's avatar
rds committed
    }

  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;
mh17's avatar
mh17 committed

  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;
mh17's avatar
mh17 committed

  //  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;
rds's avatar
rds committed
  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);
rds's avatar
rds committed
  canvas_item->auto_resize_background = TRUE;
mh17's avatar
mh17 committed
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 ;
}

mh17's avatar
mh17 committed
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 */
mh17's avatar
mh17 committed

  if (FOO_CANVAS_ITEM_GET_CLASS (item)->point)
    return FOO_CANVAS_ITEM_GET_CLASS (item)->point (item, x, y, cx, cy, actual_item);
mh17's avatar
mh17 committed

  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);
mh17's avatar
mh17 committed

  x1 = cx - item->canvas->close_enough;
  y1 = cy - item->canvas->close_enough;
  x2 = cx + item->canvas->close_enough;
  y2 = cy + item->canvas->close_enough;
mh17's avatar
mh17 committed

  best = 0.0;
  *actual_item = NULL;
mh17's avatar
mh17 committed

  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)
mh17's avatar
mh17 committed
	  && 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;
	    }
mh17's avatar
mh17 committed
	}
mh17's avatar
mh17 committed

  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 ;
}



rds's avatar
rds committed
/* Accessory functions, some copied as they were statics in foo-canvas.c */



static double get_glyph_mid_point(FooCanvasItem *item)
rds's avatar
rds committed
{
  double x, x1, x2, y1, y2;

  foo_canvas_item_get_bounds(item, &x1, &y1, &x2, &y2);
rds's avatar
rds committed
  /*     centre point           - half width          + rounding */
  x =  (((x2 - x1) * 0.5) + x1) + 0.5;
rds's avatar
rds committed

  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);
mh17's avatar
mh17 committed

rds's avatar
rds committed
      zMapWindowCanvasItemReparent(item2remove, parent_data->new_parent);
mh17's avatar
mh17 committed

rds's avatar
rds committed
      x += parent_data->x;
      y += parent_data->y;
mh17's avatar
mh17 committed

rds's avatar
rds committed
      foo_canvas_item_set(item2remove,
mh17's avatar
mh17 committed
			  "x", x,
rds's avatar
rds committed
			  "y", y,
			  NULL);
    }

  return ;
}

rds's avatar
rds committed
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
rds's avatar
rds committed

  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)
    {
mh17's avatar
mh17 committed
      colinearity = (colinear_data->compare_func)(prev_feature, curr_feature,
rds's avatar
rds committed
						  colinear_data->compare_data);
      if(colinearity != COLINEAR_INVALID)
rds's avatar
rds committed
	{
rds's avatar
rds committed
	  FooCanvasGroup *canvas_group;
rds's avatar
rds committed
	  FooCanvasItem *colinear_line;
rds's avatar
rds committed
	  double py1, py2, cy1, cy2;
rds's avatar
rds committed

rds's avatar
rds committed
	  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);

rds's avatar
rds committed
	  canvas_group = (FooCanvasGroup *)canvas_item;

rds's avatar
rds committed
	  y1 = floor(py2);
	  y2 = ceil (cy1);

rds's avatar
rds committed
	  y1 = prev_feature->x2 - canvas_group->ypos;
	  y2 = curr_feature->x1 - canvas_group->ypos - 1.0; /* Ext2Zero */

rds's avatar
rds committed
	  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;

rds's avatar
rds committed
	  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);

mh17's avatar
mh17 committed

rds's avatar
rds committed
	  zmapWindowLongItemCheckPointFull(colinear_line, &line_points, 0.0, 0.0, 0.0, 0.0);
/* 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.
mh17's avatar
mh17 committed
 *
 * 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)
rds's avatar
rds committed
    {
      start = 1 ;
      end = feature->feature.homol.y1 ;
rds's avatar
rds committed
    }
  else
    {
      start = feature->feature.homol.y2 ;
      end = feature->feature.homol.length ;
rds's avatar
rds committed
    }
  if (start < end)
    {
      int diff;
      ZMapFeatureTypeStyle style, sub_style = NULL;
      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);
            }
rds's avatar
rds committed
    }
rds's avatar
rds committed
}

rds's avatar
rds committed
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';
mh17's avatar
mh17 committed

rds's avatar
rds committed
      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;
	}
    }

edgrif's avatar
edgrif committed

#ifdef ED_G_NEVER_INCLUDE_THIS_CODE
rds's avatar
rds committed
  if(splice)
    {
//      printf("splices: %s\n", &spliceosome[0]);
rds's avatar
rds committed
    }
edgrif's avatar
edgrif committed
#endif /* ED_G_NEVER_INCLUDE_THIS_CODE */

rds's avatar
rds committed

  return splice;
}

static void process_feature(ZMapFeature prev_feature)
{
  int i;
  gboolean reversed;

  reversed = prev_feature->strand == ZMAPSTRAND_REVERSE;
mh17's avatar
mh17 committed

rds's avatar
rds committed
  if(prev_feature->feature.homol.align &&
     prev_feature->feature.homol.align->len > 1)
    {
      ZMapAlignBlock prev_align, curr_align;
mh17's avatar
mh17 committed
      prev_align = &(g_array_index(prev_feature->feature.homol.align,
rds's avatar
rds committed
				   ZMapAlignBlockStruct, 0));;
mh17's avatar
mh17 committed

rds's avatar
rds committed
      for(i = 1; i < prev_feature->feature.homol.align->len; i++)
	{
	  char *prev, *curr;
mh17's avatar
mh17 committed
	  curr_align = &(g_array_index(prev_feature->feature.homol.align,
rds's avatar
rds committed
				       ZMapAlignBlockStruct, i));
mh17's avatar
mh17 committed

rds's avatar
rds committed
	  if(prev_align->t2 + 4 < curr_align->t1)
	    {
mh17's avatar
mh17 committed
	      prev = zMapFeatureGetDNA((ZMapFeatureAny)prev_feature,
				       prev_align->t2 + 1,
				       prev_align->t2 + 2,
rds's avatar
rds committed
				       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);
	    }
mh17's avatar
mh17 committed

rds's avatar
rds committed
	  prev_align = curr_align;
	}
    }

  return ;
}