The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Bio::Graphics::Glyph::merge_parts;

use strict;
use base qw(Bio::Graphics::Glyph);

sub my_description {
    return <<END;
This is a base class for graded_segments, heterogeneous_segments,
and merged_alignment.

It adds internal methods to support semantic zooming of scored
alignment features. It is not intended for end users.
END
}

sub my_options {
    {
	max_gap => [
	    'integer',
	    undef,
	    'This is the maximum gap, measured in bp, across which the glyph will',
	    'attempt to merge subfeatures in an attempt to simplify the appearance',
	    'at low magnifications. If undef, the max_gap will be calculated using',
	    'a simple exponential heuristic.'],
    }
}

sub merge_parts {
    my ($self,@parts)  = @_;
    
    # This is the largest gap across which adjacent segments will be merged
    my $max_gap = $self->max_gap;

    my $last_part;

    my @sorted_parts = sort {$a->start <=> $b->start} @parts;

    for my $part (@sorted_parts) {
        if ($last_part) {
            my $start  = $part->start;
            my $end    = $part->stop;
            my $score  = $part->score;
            my $pstart = $last_part->start;
            my $pend   = $last_part->stop;
            my $pscore = $last_part->score || 0;
            my $len    = 1 + abs($end - $start);
            my $plen   = 1 + abs($pend - $pstart);

            # weighted average score
            my $new_score = (($score*$len)+($pscore*$plen))/($len+$plen);

            # don't merge if there is a gap > than the allowed size
            my $gap   = abs($start - $pend);
            my $total = abs($end - $pstart);

	    my $last_f = $last_part->feature;
            if ($gap > $max_gap) {
                $last_part = $part;
                next;
            }

            $part->{start}    = $pstart;
            $part->{score}    = $new_score;
            my ($left,$right) = $self->map_pt($pstart,$end+1);
            $part->{left}     = $left;
            $part->{width}    = ($right - $left) + 1;

            # flag the left feature for removal
            $last_part->{remove} = 1;
        }

        $last_part = $part;

    }

    @parts =  grep {!defined $_->{remove}} @parts;

    return @parts;
}

sub max_gap {
    my $self = shift;
    $self->panel->{max_gap} ||= $self->option('max_gap');
    return $self->panel->{max_gap} || $self->calculate_max_gap;
}

sub calculate_max_gap {
    my $self = shift;
    my $segment_length = $self->panel->length;

    # allow more aggressive merging for larger segments
    # by exponentially increasing max_gap
    my $max_gap = ($segment_length/10000)*($segment_length/500);

    $self->panel->{max_gap} = $max_gap;

    return $max_gap;
}

1;

__END__

=head1 NAME

Bio::Graphics::Glyph::merge_parts - a base class which suppors semantic zooming of scored alignment features

=head1 SYNOPSIS

  See L<Bio::Graphics::Panel> and L<Bio::Graphics::Glyph>.

=head1 DESCRIPTION

This is a base class for
Bio::Graphics::Glyph::graded_segments, 
Bio::Graphics::Glyph::heterogeneous_segments
and Bio::Graphics::Glyph::merged_alignment.
It adds internal methods to support semantic zooming of scored
alignment features. It is not intended for end users.

=head1 BUGS

Please report them.

=head1 SEE ALSO

L<Bio::Graphics::Panel>,
L<Bio::Graphics::Track>,
L<Bio::Graphics::Glyph::graded_segments>
L<Bio::Graphics::Glyph::heterogeneous_segments>
L<Bio::Graphics::Glyph::merged_alignment>

=head1 AUTHOR

Sheldon McKay E<lt>mckays@cshl.eduE<gt>

Copyright (c) 2005 Cold Spring Harbor Laboratory

    This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.  See DISCLAIMER.txt for
disclaimers of warranty.

=cut