# ALIGN2HTML
# Author: Jerome Ajot
#
# This software was developed at the National Institute of Standards and Technology by
# employees of the Federal Government in the course of their official duties. Pursuant
# to title 17 Section 105 of the United States Code this software is not subject to
# copyright protection and is in the public domain. ALIGN2HTML is an experimental system.
# NIST assumes no responsibility whatsoever for its use by other parties, and makes no
# guarantees, expressed or implied, about its quality, reliability, or any other
# characteristic. We would appreciate acknowledgement if the software is used.
#
# THIS SOFTWARE IS PROVIDED "AS IS." With regard to this software, NIST MAKES NO EXPRESS
# OR IMPLIED WARRANTY AS TO ANY MATTER WHATSOEVER, INCLUDING MERCHANTABILITY,
# OR FITNESS FOR A PARTICULAR PURPOSE.
package SegmentGroup;
use strict;
use Data::Dumper;
sub new
{
my $class = shift;
my $self = {};
$self->{ID} = shift;
$self->{REF} = {};
$self->{SYS} = {};
$self->{STARTYPOS} = 25;
$self->{YPOSSTEP} = 20;
$self->{MINX} = 10000000;
$self->{MAXX} = 0;
$self->{HEIGHT} = 0;
$self->{SPKRHEIGHT} = {};
$self->{HASFAKETIME} = 0;
$self->{SPKRYS} = {};
$self->{FILE} = shift;
$self->{CHANNEL} = shift;
$self->{NCORR} = 0;
$self->{NINS} = 0;
$self->{NSUB} = 0;
$self->{NDEL} = 0;
$self->{NREF} = 0;
$self->{NSPKRERR} = 0;
$self->{ET} = 0;
$self->{BT} = 0;
$self->{ALIGNED} = 0;
bless $self;
return $self;
}
sub unique
{
my %saw;
return grep(!$saw{$_}++, sort @_);
}
sub addRefSegment
{
my ($self, $seg) = @_;
$self->{REF}{$seg->{ID}} = $seg;
}
sub addSysSegment
{
my ($self, $seg) = @_;
$self->{SYS}{$seg->{ID}} = $seg;
}
sub ContainsFakeTimes
{
my ($self) = @_;
foreach my $segrefid(sort keys %{ $self->{REF} })
{
$self->{HASFAKETIME} = 1 if($self->{REF}{$segrefid}->{HASFAKETIME} == 1);
return;
}
foreach my $segsysid(sort keys %{ $self->{SYS} })
{
$self->{HASFAKETIME} = 1 if($self->{SYS}{$segsysid}->{HASFAKETIME} == 1);
return;
}
}
sub GetNumHypWords
{
my ($self) = @_;
my $number = 0;
foreach my $segsysid(keys %{ $self->{SYS} }) { $number += scalar keys %{ $self->{SYS}{$segsysid}->{TOKENS} } if(!($self->{SYS}{$segsysid}->HasOnlyOneFakeToken())); }
return $number;
}
sub GetToken
{
my ($self, $tokenID) = @_;
foreach my $segrefid(keys %{ $self->{REF} })
{
return $self->{REF}{$segrefid}->{TOKENS}{$tokenID} if(exists($self->{REF}{$segrefid}->{TOKENS}{$tokenID}));
}
foreach my $segsysid(keys %{ $self->{SYS} })
{
return $self->{SYS}{$segsysid}->{TOKENS}{$tokenID} if(exists($self->{SYS}{$segsysid}->{TOKENS}{$tokenID}));
}
return undef;
}
sub CalculateBeginEndTime
{
my ($self) = @_;
$self->{ET} = 0;
$self->{BT} = 1000000;
foreach my $segrefid(sort keys %{ $self->{REF} })
{
foreach my $tknid(sort keys %{ $self->{REF}{$segrefid}->{TOKENS} })
{
next if( ($self->{REF}{$segrefid}->{TOKENS}{$tknid}->{SEGBT} == 0) && ($self->{REF}{$segrefid}->{TOKENS}{$tknid}->{SEGET} == 0) && ($self->{REF}{$segrefid}->{TOKENS}{$tknid}->{TEXT} eq "") );
$self->{BT} = $self->{REF}{$segrefid}->{TOKENS}{$tknid}->{SEGBT} if($self->{REF}{$segrefid}->{TOKENS}{$tknid}->{SEGBT} < $self->{BT});
$self->{ET} = $self->{REF}{$segrefid}->{TOKENS}{$tknid}->{SEGET} if($self->{REF}{$segrefid}->{TOKENS}{$tknid}->{SEGET} > $self->{ET});
}
}
foreach my $segsysid(sort keys %{ $self->{SYS} })
{
foreach my $tknid(sort keys %{ $self->{SYS}{$segsysid}->{TOKENS} })
{
next if( ($self->{SYS}{$segsysid}->{TOKENS}{$tknid}->{BT} == 0) && ($self->{SYS}{$segsysid}->{TOKENS}{$tknid}->{BT} + $self->{SYS}{$segsysid}->{TOKENS}{$tknid}->{DUR} == 0) && ($self->{SYS}{$segsysid}->{TOKENS}{$tknid}->{TEXT} eq "") );
$self->{BT} = $self->{SYS}{$segsysid}->{TOKENS}{$tknid}->{BT} if($self->{SYS}{$segsysid}->{TOKENS}{$tknid}->{BT} < $self->{BT});
$self->{ET} = sprintf("%.3f", $self->{SYS}{$segsysid}->{TOKENS}{$tknid}->{BT} + $self->{SYS}{$segsysid}->{TOKENS}{$tknid}->{DUR}) if(sprintf("%.3f", $self->{SYS}{$segsysid}->{TOKENS}{$tknid}->{BT} + $self->{SYS}{$segsysid}->{TOKENS}{$tknid}->{DUR}) > $self->{ET});
}
}
}
sub CalculateMinMaxX
{
my ($self) = @_;
foreach my $segrefid(sort keys %{ $self->{REF} })
{
$self->{MINX} = $self->{REF}{$segrefid}->{MINX} if($self->{MINX} > $self->{REF}{$segrefid}->{MINX});
$self->{MAXX} = $self->{REF}{$segrefid}->{MAXX} if($self->{MAXX} < $self->{REF}{$segrefid}->{MAXX});
}
foreach my $segsysid(sort keys %{ $self->{SYS} })
{
$self->{MINX} = $self->{SYS}{$segsysid}->{MINX} if($self->{MINX} > $self->{SYS}{$segsysid}->{MINX});
$self->{MAXX} = $self->{SYS}{$segsysid}->{MAXX} if($self->{MAXX} < $self->{SYS}{$segsysid}->{MAXX});
}
}
sub CalculateHeigh
{
my ($self) = @_;
my %spkrYpos;
$self->{HEIGHT} = 2 * $self->{STARTYPOS} + $self->{YPOSSTEP};
foreach my $segrefid(sort keys %{ $self->{REF} })
{
my $spkrID = $self->{REF}{$segrefid}->{SPKRID};
if(!exists($spkrYpos{REF}{$spkrID}))
{
$spkrYpos{REF}{$spkrID} = 1;
$self->{SPKRHEIGHT}{$spkrID} = $self->{REF}{$segrefid}->{HEIGHT};
}
else
{
$self->{SPKRHEIGHT}{$spkrID} = $self->{REF}{$segrefid}->{HEIGHT} if($self->{REF}{$segrefid}->{HEIGHT} > $self->{SPKRHEIGHT}{$spkrID});
}
}
foreach my $segsysid(sort keys %{ $self->{SYS} })
{
my $spkrID = $self->{SYS}{$segsysid}->{SPKRID};
if(!exists($spkrYpos{SYS}{$spkrID}))
{
$spkrYpos{SYS}{$spkrID} = 1;
$self->{SPKRHEIGHT}{$spkrID} = $self->{SYS}{$segsysid}->{HEIGHT};
}
else
{
$self->{SPKRHEIGHT}{$spkrID} = $self->{SYS}{$segsysid}->{HEIGHT} if($self->{SYS}{$segsysid}->{HEIGHT} > $self->{SPKRHEIGHT}{$spkrID});
}
}
foreach my $idd (keys %{ $self->{SPKRHEIGHT} } )
{
$self->{HEIGHT} += $self->{SPKRHEIGHT}{$idd} + $self->{YPOSSTEP};
}
return $self->{HEIGHT};
}
sub SetYs
{
my ($self) = @_;
my $output = "";
my $currYpos = $self->{STARTYPOS};
my $YposStep = $self->{YPOSSTEP};
my %spkrYpos;
foreach my $segrefid(sort keys %{ $self->{REF} })
{
my $spkrID = $self->{REF}{$segrefid}->{SPKRID};
my $Ypos;
if(!exists($spkrYpos{REF}{$spkrID}))
{
$Ypos = $currYpos;
$spkrYpos{REF}{$spkrID} = $Ypos;
$currYpos += $self->{SPKRHEIGHT}{$spkrID} + $YposStep;
}
else
{
$Ypos = $spkrYpos{REF}{$spkrID};
}
$self->{REF}{$segrefid}->SetY($Ypos);
$self->{SPKRYS}{$spkrID} = $Ypos;
}
$currYpos += 2*$self->{YPOSSTEP};
foreach my $segsysid(sort keys %{ $self->{SYS} })
{
my $spkrID = $self->{SYS}{$segsysid}->{SPKRID};
my $Ypos;
if(!exists($spkrYpos{SYS}{$spkrID}))
{
$Ypos = $currYpos;
$spkrYpos{SYS}{$spkrID} = $Ypos;
$currYpos += $self->{SPKRHEIGHT}{$spkrID} + $YposStep;
}
else
{
$Ypos = $spkrYpos{SYS}{$spkrID};
}
$self->{SYS}{$segsysid}->SetY($Ypos);
$self->{SPKRYS}{$spkrID} = $Ypos;
}
}
sub GetFillREFHYP
{
my ($self, $maxscalewidth) = @_;
my $output = "";
my @valuessep1;
foreach my $spkrID(sort keys %{ $self->{SPKRYS} })
{
push(@valuessep1, $self->{SPKRYS}{$spkrID} - 25);
push(@valuessep1, $self->{SPKRYS}{$spkrID} + $self->{SPKRHEIGHT}{$spkrID});
}
my @valuessep = sort {$a <=> $b} @valuessep1;
my @refspkrs;
foreach my $segref (keys %{ $self->{REF} }) { push(@refspkrs, $self->{REF}{$segref}->{SPKRID}); }
my $nrefspkr = scalar unique @refspkrs;
my @sysspkrs;
foreach my $segsys (keys %{ $self->{SYS} }) { push(@sysspkrs, $self->{SYS}{$segsys}->{SPKRID}); }
my $nsysspkr = scalar unique @sysspkrs;
if($nrefspkr == 0)
{
my $y1 = $valuessep[0];
my $y2 = $valuessep[scalar(@valuessep) - 1];
$output .= sprintf("jg.setColor(\"#ffeeee\");\n");
$output .= sprintf("jg.fillRect(0, %.0f, scale*%.0f - 1, %.0f);\n", $y1 + 1, $maxscalewidth, $y2 - $y1 - 1);
}
elsif($nsysspkr == 0)
{
my $y1 = $valuessep[0];
my $y2 = $valuessep[scalar(@valuessep) - 1];
$output .= sprintf("jg.setColor(\"#eeffee\");\n");
$output .= sprintf("jg.fillRect(0, %.0f, scale*%.0f - 1, %.0f);\n", $y1 + 1, $maxscalewidth, $y2 - $y1 - 1);
}
else
{
my $y1 = $valuessep[0];
my $ym = ($valuessep[2*$nrefspkr - 1] + $valuessep[2*$nrefspkr])/2;
my $y2 = $valuessep[scalar(@valuessep) - 1];
$output .= sprintf("jg.setColor(\"#eeffee\");\n");
$output .= sprintf("jg.fillRect(0, %.0f, scale*%.0f - 1, %.0f);\n", $y1 + 1, $maxscalewidth, $ym - $y1 - 1);
$output .= sprintf("jg.setColor(\"#ffeeee\");\n");
$output .= sprintf("jg.fillRect(0, %.0f, scale*%.0f - 1, %.0f);\n", $ym - $y1 + 1, $maxscalewidth, $y2 - $ym -1);
}
return $output;
}
sub GetSeparationLines
{
my ($self, $maxscalewidth) = @_;
my $output = "";
$output .= sprintf("jg.setColor(\"black\");\n");
$output .= sprintf("jg.setFont(\"verdana\",\"12px\",Font.PLAIN);\n");
foreach my $spkrID(sort keys %{ $self->{SPKRYS} })
{
my $spkName = $spkrID;
$spkName =~ s/^ref://;
$spkName =~ s/^hyp://;
$output .= sprintf("jg.drawStringRect(\"%s\",%.0f, %.0f, scale*%.0f, \"left\");\n", $spkName, 0, $self->{SPKRYS}{$spkrID} - 8 + ($self->{SPKRHEIGHT}{$spkrID}-30)/2, $maxscalewidth);
}
$output .= sprintf("jg.setColor(\"yellow\");\n");
$output .= sprintf("jg.setStroke(1);\n");
my @valuessep1;
foreach my $spkrID(sort keys %{ $self->{SPKRYS} })
{
push(@valuessep1, $self->{SPKRYS}{$spkrID} - 25);
push(@valuessep1, $self->{SPKRYS}{$spkrID} + $self->{SPKRHEIGHT}{$spkrID});
}
my @valuessep = sort {$a <=> $b} @valuessep1;
$output .= sprintf("jg.drawLine(0, %.0f, scale*%.0f - 1, %.0f);\n", $valuessep[0], $maxscalewidth, $valuessep[0]);
for(my $i=1; $i{REF} })
{
$self->{REF}{$segrefid}->Compute();
}
foreach my $segsysid(sort keys %{ $self->{SYS} })
{
$self->{SYS}{$segsysid}->Compute();
}
$self->CalculateMinMaxX();
$self->CalculateHeigh();
$self->ContainsFakeTimes();
$self->SetYs();
$self->CalculateBeginEndTime();
}
sub isInSpeakers
{
my ($self, $spkr) = @_;
foreach my $segrefid(sort keys %{ $self->{REF} })
{
return 1 if($self->{REF}{$segrefid}->{SPKRID} =~ /^$spkr$/i);
}
foreach my $segsysid(sort keys %{ $self->{SYS} })
{
return 1 if($self->{SYS}{$segsysid}->{SPKRID} =~ /^$spkr$/i);
}
return 0;
}
sub GetDraw
{
my ($self, $decalx) = @_;
my $output = "";
foreach my $segrefid(sort keys %{ $self->{REF} })
{
$output .= $self->{REF}{$segrefid}->GetDraw($self->{MINX} - $decalx);
}
foreach my $segsysid(sort keys %{ $self->{SYS} })
{
$output .= $self->{SYS}{$segsysid}->GetDraw($self->{MINX} - $decalx);
}
return $output;
}
1;