#======================================================== # GraphScale #======================================================== package GraphScale; #use Tk::Frame; #@ISA = qw(Tk::Frame); #公開したいサブルーチン #@EXPORT = qw(); use strict; use Rect; #============================================================ # 変数等取得関数 #============================================================ sub mw { return shift->{'MainWindow'}; } sub MainWindow { return shift->{'MainWindow'}; } #sub Canvas { return shift->{'Canvas'}; } sub Canvas { my ($this, $canvas) = @_; if($canvas) { return $canvas; } return $this->mw()->Canvas(); } sub Index { return shift->{'Index'}; } sub nMaxScale { return shift->{'nMaxScale'}; } sub SetnMaxScale { my ($this,$nmax) =@_; return $this->{'nMaxScale'} = $nmax; } sub Caption { return shift->{'Caption'}; } sub SetCaption { my ($this,$caption)=@_; return $this->{'Caption'} = $caption; } sub ScalePosition { return shift->{'ScalePosition'}; }; sub SetScalePosition { my ($this,$pos)=@_; return $this->{'ScalePosition'} = $pos; } sub IsXScale { return shift->{'ScalePosition'} =~ /^x/i; } sub IsYScale { return shift->{'ScalePosition'} =~ /^y/i; } sub ScaleStringVisible { return shift->{'ScaleStringVisible'}; } sub SetScaleStringVisible { my ($this, $visible) = @_; return $this->{'ScaleStringVisible'} = $visible; } sub ScaleVisible { return shift->{'ScaleVisible'}; } sub SetScaleVisible { my ($this, $visible) = @_; return $this->{'ScaleVisible'} = $visible; } sub CaptionVisible { return shift->{'CaptionVisible'}; } sub SetCaptionVisible { my ($this, $visible) = @_; return $this->{'CaptionVisible'} = $visible; } sub ScaleFormat { my ($this) = @_; my $format = $this->{'ScaleFormat'}; $format = "%g" unless($format); return $format } sub SetScaleFormat { my ($this, $format) = @_; return $this->{'ScaleFormat'} = $format; } sub SetIndex { my ($this, $idx) = @_; return $this->{'Index'} = $idx; } sub SetFont { my ($this, $pFont) = @_; return $this->{'pFont'} = $pFont; } #============================================================ # コンストラクタ、デストラクタ #============================================================ sub new { my ($module, $mainwindow, $position, $idx) = @_; # my ($module, $mainwindow, $canvas, $position, $idx) = @_; my $this = {}; bless $this; $idx = 0 unless($idx); $position = 'xbottom' unless($position); # $this->{'Canvas'} = $canvas; $this->{'MainWindow'} = $mainwindow; $this->SetIndex($idx); $this->SetScalePosition($position); $this->SetScaleStringVisible(1); $this->SetScaleVisible(1); $this->SetCaptionVisible(1); $this->SetnMaxScale(10); $this->SetCaption('X'); return $this; } sub DESTROY { my $this = shift; # $this->SUPER::DESTROY(@_); } #============================================================ # 一般関数 #============================================================ sub Draw { my ($this, $canvas) = @_; $canvas = $this->Canvas($canvas); my $r = new Rect; if($this->{'ScalePosition'} =~ /^x/i) { return $r->Merge($this->DrawXScale($canvas)); } return $r->Merge($this->DrawYScale($canvas)); } sub DrawXScale { my ($this, $canvas) = @_; $canvas = $this->Canvas(); my $xf = $this->{"Func"}; my $xs = $this->{"Swap"}; my $idx = $this->Index(); my $pos = $this->ScalePosition(); my $XScaleWidth = 2; my $XSubScaleWidth = 1; my $XScaleLength = 5; my $XScaleCharMargin = 5; my $x0 = $this->{'x0'}; my $y0 = $this->{'y0'}; my $x1 = $this->{'x1'}; my $y1 = $this->{'y1'}; my $vx0 = $this->{'ViewX0'}; my $vx1 = $this->{'ViewX1'}; ($vx1, $vx0) = ($vx0, $vx1) if($xs); my $font = $canvas->CreateFont("times", 16, "normal"); $font = $this->{'pFont'} if($this->{'pFont'}); my $format = $this->ScaleFormat(); my $StrVisible = $this->ScaleStringVisible(); my $ScaleVisible = $this->ScaleVisible(); my $CaptionVisible = $this->CaptionVisible(); #print "x=$x0,$y0,$x1,$y1\n"; my $rXScale; if($pos eq 'xbottom') { $rXScale = new Rect($x0, $y0, $x1, $y0); $canvas->DrawLine($x0, $y0, $x1, $y0, $XScaleWidth, "", "XScale$idx") if($ScaleVisible); } elsif($pos eq 'xtop') { $rXScale = new Rect($x0, $y1, $x1, $y1); $canvas->DrawLine($x0, $y1, $x1, $y1, $XScaleWidth, "", "XScale$idx") if($ScaleVisible); } for(my $i = 0 ; $i < $this->{'nScale'} ; $i++) { my $v = $this->{'ScaleStart'} + $i*$this->{'ScaleStep'}; my $x = $this->ValueToPosition($v, 'X'); my $r = ($x - $x0) / ($x1 - $x0); next if($r < 0 or 1.0 < $r); if($ScaleVisible) { my $rt; if($pos eq 'xbottom') { $rt = $canvas->DrawLine($x, $y0, $x, $y0-$XScaleLength, $XSubScaleWidth, '', "XScale$idx"); } elsif($pos eq 'xtop') { $rt = $canvas->DrawLine($x, $y1, $x, $y1+$XScaleLength, $XSubScaleWidth, '', "XScale$idx"); } $rXScale->Merge($rt); } my $s = sprintf($format, $v); Utils::DelSpace($s); if($pos eq 'xbottom') { my $y = $y0+$XScaleCharMargin; $rXScale->Merge( $canvas->DrawText($x, $y, $s, $font, 'n', '', "XScale$idx") ) if($StrVisible); } elsif($pos eq 'xtop') { my $y = $y1-$XScaleCharMargin; $rXScale->Merge( $canvas->DrawText($x, $y, $s, $font, 's', '', "XScale$idx") ) if($StrVisible); } } if($CaptionVisible) { my $rXCaption; if($pos eq 'xbottom') { $rXCaption = $canvas->DrawText( ($x0+$x1)/2.0, $rXScale->y1()+$XScaleCharMargin, $this->Caption(), $font, "n", '', "XCaption$idx"); $canvas->{"XCaption${idx}Rect"} = $rXCaption->x0() . "," . $rXCaption->y0() . "," . $rXCaption->x1() . "," . $rXCaption->y1(); } elsif($pos eq 'xtop') { $rXCaption = $canvas->DrawText( ($x0+$x1)/2.0, $rXScale->y0()-$XScaleCharMargin, $this->Caption(), $font, "s", '', "XCaption$idx"); $canvas->{"XCaption${idx}Rect"} = $rXCaption->x0() . "," . $rXCaption->y0() . "," . $rXCaption->x1() . "," . $rXCaption->y1(); } } $canvas->{"XScale${idx}Rect"} = $rXScale->x0() . "," . $rXScale->y0() . "," . $rXScale->x1() . "," . $rXScale->y1(); return $rXScale; } sub DrawYScale { my ($this, $canvas) = @_; $canvas = $this->Canvas(); my $xf = $this->{"Func"}; my $xs = $this->{"Swap"}; my $pos = $this->ScalePosition(); my $idx = $this->Index(); my $YScaleWidth = 2; my $YSubScaleWidth = 1; my $YScaleLength = 5; my $YScaleCharMargin = 10; my $x0 = $this->{'x0'}; my $y0 = $this->{'y0'}; my $x1 = $this->{'x1'}; my $y1 = $this->{'y1'}; my $vy0 = $this->{'ViewY0'}; my $vy1 = $this->{'ViewY1'}; ($vy1, $vy0) = ($vy0, $vy1) if($xs); my $font = $canvas->CreateFont('times', 16, 'normal'); $font = $this->{'pFont'} if($this->{'pFont'}); my $format = $this->ScaleFormat(); my $StrVisible = $this->ScaleStringVisible(); my $ScaleVisible = $this->ScaleVisible(); my $CaptionVisible = $this->CaptionVisible(); my $rYScale; if($pos eq 'yleft') { $rYScale = new Rect($x0, $y0, $x0, $y1); $canvas->DrawLine($x0, $y0, $x0, $y1, $YScaleWidth, '', "YScale$idx") if($ScaleVisible); } elsif($pos eq 'yright') { $rYScale = new Rect($x1, $y0, $x1, $y1); $canvas->DrawLine($x1, $y0, $x1, $y1, $YScaleWidth, '', "YScale$idx") if($ScaleVisible); } for(my $i = 0 ; $i < $this->{'nScale'} ; $i++) { my $v = $this->{'ScaleStart'} + $i*$this->{'ScaleStep'}; my $y = $this->ValueToPosition($v, 'Y'); my $r = ($y - $y0) / ($y1 - $y0); next if($r < 0 or 1.0 < $r); if($pos eq 'yleft') { $rYScale->Merge( $canvas->DrawLine($x0, $y, $x0+$YScaleLength, $y, $YSubScaleWidth, '', "YScale$idx") ) if($ScaleVisible); my $x = $x0-$YScaleCharMargin; my $s = sprintf($format, $v); Utils::DelSpace($s); $rYScale->Merge( $canvas->DrawText($x, $y, $s, $font, 'e', '', "YScale$idx") ) if($StrVisible); } elsif($pos eq 'yright') { $rYScale->Merge( $canvas->DrawLine($x1, $y, $x1-$YScaleLength, $y, $YSubScaleWidth, '', "YScale$idx") ) if($ScaleVisible); my $x = $x1+$YScaleCharMargin; my $s = sprintf($format, $v); Utils::DelSpace($s); $rYScale->Merge( $canvas->DrawText($x, $y, $s, $font, 'w', '', "YScale$idx") ) if($StrVisible); } } if($CaptionVisible) { my $rYCaption; if($pos eq 'yleft') { $rYCaption = $canvas->DrawText($rYScale->x0()-$YScaleCharMargin, $y1-$YScaleCharMargin, $this->Caption(), $font, 'sw', '', "YCaption$idx"); $canvas->{"YCaption${idx}Rect"} = $rYCaption->x0() . "," . $rYCaption->y0() . "," . $rYCaption->x1() . "," . $rYCaption->y1(); } elsif($pos eq 'yright') { $rYCaption = $canvas->DrawText($rYScale->x1()+$YScaleCharMargin, $y1-$YScaleCharMargin, $this->Caption(), $font, 'se', '', "YCaption$idx"); $canvas->{"YCaption${idx}Rect"} = $rYCaption->x0() . "," . $rYCaption->y0() . "," . $rYCaption->x1() . "," . $rYCaption->y1(); } } $canvas->{"YScale${idx}Rect"} = $rYScale->x0() . "," . $rYScale->y0() . "," . $rYScale->x1() . "," . $rYScale->y1(); return $rYScale; } sub ValueToPosition { my ($this, $v, $scale) = @_; my $xf = $this->{"Func"}; my $xs = $this->{"Swap"}; $v = &$xf($v); #print "v:$v xf: $xf\n"; my $x; if($scale =~ /x/i) { my $vx0 = &$xf($this->{'ViewX0'}); my $vx1 = &$xf($this->{'ViewX1'}); my $dx = $vx1 - $vx0; $dx = 1.0 if($dx == 0.0); my $r = ($this->{'x1'} - $this->{'x0'}) / $dx; $x = $this->{'x0'} + $r * ($v - $vx0); } else { my $vy0 = &$xf($this->{'ViewY0'}); my $vy1 = &$xf($this->{'ViewY1'}); ($vy1, $vy0) = ($vy0, $vy1) if($xs); #print "v:$v ($vy0,$vy1): xf: $xf\n"; my $dy = $vy1 - $vy0; $dy = 1.0 if($dy == 0.0); my $r = ($this->{'y1'} - $this->{'y0'}) / $dy; $x = $this->{'y0'} + $r * ($v - $vy0); } return $x; } sub CalScale { my ($this, $x0, $x1, $nmaxscale) = @_; if($this->ScalePosition() =~ /^x/i) { $x0 = $this->{'ViewX0'}+0.0 unless(defined $x0); $x1 = $this->{'ViewX1'}+0.0 unless(defined $x1); } else { $x0 = $this->{'ViewY0'}+0.0 unless(defined $x0); $x1 = $this->{'ViewY1'}+0.0 unless(defined $x1); } $nmaxscale = $this->nMaxScale() unless($nmaxscale); $nmaxscale = 1 if($nmaxscale < 1); $nmaxscale = 12.0 if($nmaxscale > 12.0); my $flag = 1; if($x0 > $x1) { $flag = -1; ($x1, $x0) = ($x0, $x1); } $x1 = $x0 * 1.1 if($x0 == $x1); $x1 = $x0 + 1.0 if($x0 == $x1); my $lx = abs($x1 - $x0); my $bairitu = 1.0; while($lx * $bairitu < $nmaxscale / 10.0) { last if($bairitu >= 1.0e100); $bairitu *= 10.0; } while($lx * $bairitu >= $nmaxscale) { last if($bairitu <= 1.0e-100); $bairitu /= 10.0; } while($lx * $bairitu < $nmaxscale / 5.0) { last if($bairitu >= 1.0e100); $bairitu *= 5.0; } while($lx * $bairitu < $nmaxscale / 2.0) { last if($bairitu >= 1.0e100); $bairitu *= 2.0; } my $step = 1.0 / $bairitu * $flag; $step = 1.0 if($step == 0.0); my $start = int($x0 * $bairitu) / $bairitu; for(my $i = 0 ; $i < 20 ; $i++) { if($flag == 1) { $start += $step; if($start >= $x0) { $start -= 2.0 * $step; last; } } else { if($start <= $x0) { $start -= 2.0 * $step; last; } $start += $step; } } my $end = $x1; my $dx = $end - $start; my $nscale = int( $dx / $step + 1.01 ) + 1; $this->{'ScaleStart'} = $start; $this->{'ScaleEnd'} = $end; $this->{'ScaleStep'} = $step; $this->{'nScale'} = $nscale; #print "x0=$x0 x1=$x1: $start, $end, $step, $nscale\n"; return ($start, $end, $step, $nscale); } sub SetViewXRange { my ($this, $x0, $x1) = @_; #print "x: $x0- $x1\n"; $this->{'ViewX0'} = $x0+0.0; $this->{'ViewX1'} = $x1+0.0; $this->CalScale($x0, $x1, $this->nMaxScale()); } sub SetViewYRange { my ($this, $y0, $y1) = @_; my $nScaleY = 10; $this->{'ViewY0'} = $y0+0.0; $this->{'ViewY1'} = $y1+0.0; $this->CalScale($y0, $y1, $this->nMaxScale()); } sub SetViewRange { my ($this, $x0, $y0, $x1, $y1) = @_; $this->SetViewXRange($x0, $x1); $this->SetViewYRange($y0, $y1); } sub SetPosition { my ($this, $x0, $y0, $x1, $y1) = @_; $this->{'x0'} = $x0; $this->{'y0'} = $y0; $this->{'x1'} = $x1; $this->{'y1'} = $y1; } sub SetPositionByStr { my ($this, $str) = @_; my ($x0, $y0, $x1, $y1) = ($str =~ /^(\d+),(\d+),(\d+),(\d+)/); $this->SetPosition($x0, $y0, $x1, $y1); } 1;