#======================================================== # GraphFrame #======================================================== package GraphFrame; use MyTk::TkCommon; @ISA = qw(TkCommon); #公開したいサブルーチン #@EXPORT = qw(); use strict; use MyTk::GraphScale; use MyTk::Dialog; use MyTk::Shape; use Rect; use PlotData; use CSV; #============================================================ # ローカル大局変数 #============================================================ my @PredefinedColors = ("black", "red", "blue", "brown", "purple", "violet", "cyan", "magenta", "green", "yellow", "pink", "orange1", "grey", "dark red", "dark blue", "brown4", "purple3", "dark violet", "dark cyan", "dark magenta", "dark green", "yellow4", "DeepPink1", "white"); my $nColors = @PredefinedColors; my $CurColor = 0; #============================================================ # 静的メンバー関数 #============================================================ sub SetScalePlotType { my ($object, $axis, $type) = @_; $type = 'x' unless($type); #print "set $axis to $type\n"; $object->{"${axis}ScalePlotType"} = $type; if($type eq '' or $type eq 'x') { $object->{"${axis}Func"} = \&Sci::FuncLinear; $object->{"${axis}IFunc"} = \&Sci::FuncLinear; $object->{"${axis}Swap"} = 0; $object->{"${axis}Abs"} = 0; } if($type eq '' or $type eq '-x') { $object->{"${axis}Func"} = \&Sci::FuncMinus; $object->{"${axis}IFunc"} = \&Sci::FuncMinus; $object->{"${axis}Swap"} = 1; $object->{"${axis}Abs"} = 0; } elsif($type eq 'log(x)') { $object->{"${axis}Func"} = \&Sci::FuncLog10; $object->{"${axis}IFunc"} = \&Sci::FuncPower10; $object->{"${axis}Swap"} = 0; $object->{"${axis}Abs"} = 0; } elsif($type eq 'log(|x|)') { $object->{"${axis}Func"} = \&Sci::FuncLog10Abs; $object->{"${axis}IFunc"} = \&Sci::FuncPower10; $object->{"${axis}Swap"} = 0; $object->{"${axis}Abs"} = 1; } elsif($type eq 'ln(x)') { $object->{"${axis}Func"} = \&Sci::FuncLn; $object->{"${axis}IFunc"} = \&Sci::FuncExp; $object->{"${axis}Swap"} = 0; $object->{"${axis}Abs"} = 0; } elsif($type eq 'ln(|x|)') { $object->{"${axis}Func"} = \&Sci::FuncLnAbs; $object->{"${axis}IFunc"} = \&Sci::FuncExp; $object->{"${axis}Swap"} = 0; $object->{"${axis}Abs"} = 1; } elsif($type eq '1/x') { $object->{"${axis}Func"} = \&Sci::FuncInverse; $object->{"${axis}IFunc"} = \&Sci::FuncInverse; $object->{"${axis}Swap"} = 1; $object->{"${axis}Abs"} = 0; } } sub ResetCurColor { $CurColor = 0; } sub GetColor { my ($idx) = @_; $idx = $CurColor unless($idx); return $PredefinedColors[$idx % ($nColors-1)]; } #============================================================ # 変数等取得関数 #============================================================ sub App { return shift->mw()->App(); } sub Application { return shift->mw()->App(); } sub MainMenu { return shift->mw()->MainMenu(); } 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 SetCanvas { my ($this,$c)=@_; return shift->{'Canvas'} = $c; } sub GraphScaleArray { return shift->{'GraphScaleArray'}; } sub Index { return shift->{'Index'}; } sub CanvasHeight { return shift->{'CanvasHeight'}; } sub CanvasWidth { return shift->{'CanvasWidth'}; } sub GetViewXRange { my $this=shift; return ($this->{'ViewX0'}, $this->{'ViewX1'}); } sub GetViewYRange { my $this=shift; return ($this->{'ViewY0'}, $this->{'ViewY1'}); } sub GetViewRange { my $this=shift; return ($this->{'ViewX0'}, $this->{'ViewY0'}, $this->{'ViewX1'}, $this->{'ViewY1'}); } sub GetPosition { my $this=shift; return ($this->{'x0'}, $this->{'y0'}, $this->{'x1'}, $this->{'y1'}); } sub nDataArray { my $da=shift->{'DataArray'}; return @$da; }; sub GetnGraphData { my ($this) = @_; my $pDataArray = $this->{'DataArray'}; return scalar @$pDataArray; } sub GetPlotData { my ($this, $idx) = @_; $idx = 0 unless(defined $idx); return $this->{'DataArray'}->[$idx]; } sub GetXYGraphDataRefs { my ($this, $idx) = @_; $idx = 0 unless(defined $idx); return ($this->{'DataArray'}->[$idx]->GetXArrayRef(), $this->{'DataArray'}->[$idx]->GetYArrayRef()); } sub SetSmoothLine { my ($this,$f)=@_; return $this->{'SmoothLine'} = $f; } sub SmoothLine { my ($this)=@_; return $this->{'SmoothLine'}; } sub SetIndex { my ($this,$i)=@_; return $this->{'Index'} = $i; } sub XScalePlotType { return shift->{'XScalePlotType'}; } sub YScalePlotType { return shift->{'YScalePlotType'}; } sub BottomLineVisible { return shift->{'BottomLineVisible'}; } sub RightLineVisible { return shift->{'RightLineVisible'}; } sub TopLineVisible { return shift->{'TopLineVisible'}; } sub LeftLineVisible { return shift->{'LeftLineVisible'}; } sub SetX0LineVisible { my ($this,$f)=@_; return shift->{'X0LineVisible'} = $f; } sub X0LineVisible { return shift->{'X0LineVisible'}; } sub SetY0LineVisible { my ($this,$f)=@_; return shift->{'Y0LineVisible'} = $f; } sub Y0LineVisible { return shift->{'Y0LineVisible'}; } sub SetBottomLineVisible { my ($this,$f)=@_; return shift->{'BottomLineVisible'} = $f; } sub SetRightLineVisible { my ($this,$f)=@_; return shift->{'RightLineVisible'} = $f; } sub SetTopLineVisible { my ($this,$f)=@_; return shift->{'TopLineVisible'} = $f; } sub SetLeftLineVisible { my ($this,$f)=@_; return shift->{'LeftLineVisible'} = $f; } sub SetLinesVisible { my ($this, $left, $right, $top, $bottom, $x0, $y0) = @_; $this->SetBottomLineVisible($bottom); $this->SetRightLineVisible($right); $this->SetTopLineVisible($top); $this->SetLeftLineVisible($left); $this->SetX0LineVisible($x0); $this->SetY0LineVisible($y0); } sub SetFlipX { my ($this, $f) = @_; return $this->{FlipX} = $f; } sub SetFlipY { my ($this, $f) = @_; return $this->{FlipY} = $f; } sub SetFlipXY { my ($this, $fx, $fy) = @_; $this->{FlipX} = $fx; $this->{FlipY} = $fy; } sub XMin { return shift->{XMin}; } sub XMax { return shift->{XMax}; } sub YMin { return shift->{YMin}; } sub YMax { return shift->{YMax}; } sub XRange { my ($this, $ConvertFunc, $FillWithValue) = @_; my $x0 = (!defined $this->{XMin} and $FillWithValue)? 0.0 : $this->{XMin}; my $x1 = (!defined $this->{XMax} and $FillWithValue)? 1.0 : $this->{XMax}; if($ConvertFunc) { my $xf = $this->{XFunc}; ($x0, $x1) = (&$xf($x0), &$xf($x1)); } return ($x0, $x1) = Utils::Sort($x0, $x1); } sub YRange { my ($this, $ConvertFunc, $FillWithValue) = @_; my $y0 = (!defined $this->{YMin} and $FillWithValue)? 0.0 : $this->{YMin}; my $y1 = (!defined $this->{YMax} and $FillWithValue)? 1.0 : $this->{YMax}; if($ConvertFunc) { my $yf = $this->{YFunc}; ($y0, $y1) = (&$yf($y0), &$yf($y1)); } return ($y0, $y1) = Utils::Sort($y0, $y1); } sub XYRange { my ($this, $ConvertFunc, $FillWithValue) = @_; my ($x0, $x1) = $this->XRange($ConvertFunc, $FillWithValue); my ($y0, $y1) = $this->YRange($ConvertFunc, $FillWithValue); return ($x0, $y0, $x1, $y1); } sub CalMaxMarginRange { my ($this, $marginx0, $marginx1, $marginy0, $marginy1) = @_; $marginx0 = (defined $this->{MarginX0})? $this->{MarginX0} : 0.0 unless(defined $marginx0); $marginx1 = (defined $this->{MarginX1})? $this->{MarginX1} : 0.0 unless(defined $marginx1); $marginy0 = (defined $this->{MarginY0})? $this->{MarginY0} : $marginx0 unless(defined $marginy0); $marginy1 = (defined $this->{MarginY1})? $this->{MarginY1} : $marginx1 unless(defined $marginy1); ($this->{MarginX0}, $this->{MarginX1}, $this->{MarginY0}, $this->{MarginY1}, ) = ($marginx0, $marginx1, $marginy0, $marginy1); my ($xmin, $ymin, $xmax, $ymax) = $this->XYRange(1, 1); my ($xrange, $yrange) = ($xmax - $xmin, $ymax - $ymin); my ($xm0, $xm1) = ($xmin - $xrange * $marginx0, $xmax + $xrange * $marginx1); my ($ym0, $ym1) = ($ymin - $yrange * $marginy0, $ymax + $yrange * $marginy0); return ($xm0, $ym0, $xm1, $ym1); } #============================================================ # コンストラクタ、デストラクタ #============================================================ sub new($$) { my ($module, $mainwindow, $idx) = @_; # my ($module, $mainwindow, $canvas, $idx) = @_; my $this = {}; bless $this; # $this->{'Canvas'} = $canvas; $this->{'MainWindow'} = $mainwindow; $idx = 0 unless($idx); my @DataArray; $this->{'DataArray'} = \@DataArray; my @array; $this->{'GraphScaleArray'} = \@array; my @SXArray; $this->{'XSynchronousGraphFrameArray'} = \@SXArray; my @SYArray; $this->{'YSynchronousGraphFrameArray'} = \@SYArray; $this->SetIndex($idx); $this->{'XCaption'} = "Energy / eV"; $this->{'YCaption'} = "Intensity / cps"; $this->AddXScale("xbottom", "x"); # $this->AddXScale("xtop", "x"); $this->AddYScale("yleft", "x"); # $this->AddYScale("yright", "x"); $this->SetLinesVisible(1, 1, 1, 1, 1, 1); $this->SetViewRange(0, 0, 1, 1); $CurColor = 0; return $this; } sub DESTROY { my $this = shift; # $this->SUPER::DESTROY(@_); } #============================================================ # 一般関数 #============================================================ sub IsInside { my ($this, $x, $y) = @_; my $x0 = $this->{'x0'}; my $y0 = $this->{'y0'}; my $x1 = $this->{'x1'}; my $y1 = $this->{'y1'}; my $r = ($x - $x0) / ($x1 - $x0); return 0 if($r < 0 or 1.0 < $r); $r = ($y - $y0) / ($y1 - $y0); return 0 if($r < 0 or 1.0 < $r); return 1; } sub AddXScale { my ($this, $position, $plottype) = @_; my $idx = $this->Index(); $this->{'GraphScaleX'} = new GraphScale($this->mw(), $position, $idx); # = new GraphScale($this->mw(), $this->Canvas(), $position, $idx); my $pArray = $this->{'GraphScaleArray'}; push(@$pArray, $this->{'GraphScaleX'}); $plottype = $this->XScalePlotType() unless($plottype); $plottype = "x" unless($plottype); $this->SetXScalePlotType($plottype, 0); } sub AddYScale { my ($this, $position, $plottype) = @_; my $idx = $this->Index(); $this->{'GraphScaleY'} = new GraphScale($this->mw(), $position, $idx); # = new GraphScale($this->mw(), $this->Canvas(), $position, $idx); my $pArray = $this->{'GraphScaleArray'}; push(@$pArray, $this->{'GraphScaleY'}); $plottype = $this->YScalePlotType() unless($plottype); $plottype = "x" unless($plottype); $this->SetYScalePlotType($plottype, 0); } sub SaveCSVFile { my ($this, $path, $LimitToViewYRange) = @_; my ($ViewYMin, $ViewYMax) = $this->GetViewYRange(); my $pDataArray = $this->{'DataArray'}; my $nDataArray = $this->nDataArray(); return undef if($nDataArray == 0); my @DataArray; my @LabelNameArray; my $c = 0; my $PrevnData = 0; my $PrevXMin = 1.0e30; my $PrevXMax = -1.0e30; my $PrevX1 = 1.0e30; my $PrevX2 = 1.0e30; my $PrevX3 = 1.0e30; for(my $i = 0 ; $i < $nDataArray ; $i++) { my $pData = $pDataArray->[$i]; my $pXArray = $pData->GetXArrayRef(); my $pYArray = $pData->GetYArrayRef(); my $nData = $pData->nData(); my ($XMin, $XMax) = $pData->GetXMinMax(); my ($YMin, $YMax) = $pData->GetYMinMax(); #print "$LimitToViewYRange: ?($ViewYMax < $YMin) or ?($ViewYMin > $YMax)\n"; if($LimitToViewYRange) { next if($ViewYMax < $YMin or $ViewYMin > $YMax); } my $X1 = $pData->X(int($nData/3)); my $X2 = $pData->X(int($nData/2)); my $X3 = $pData->X(int($nData*2/3)); if($nData != $PrevnData or abs($XMin-$PrevXMin) > 1.0e-60 or abs($XMax-$PrevXMax) > 1.0e-60 or abs($X1-$PrevX1) > 1.0e-60 or abs($X2-$PrevX2) > 1.0e-60 or abs($X3-$PrevX3) > 1.0e-60 ) { my $XName = $pData->GetXName(); unless($XName) { my $i1 = $i+1; $XName = "XData-$i1"; } $LabelNameArray[$c] = $XName; $DataArray[$c] = $pXArray; $c++; } my $YName = $pData->GetYName(); unless($YName) { my $i1 = $i+1; $YName = "YData-$i1"; } $LabelNameArray[$c] = $YName; $DataArray[$c] = $pYArray; $c++; $PrevnData = $nData;; $PrevXMin = $XMin; $PrevXMax = $XMax; $PrevX1 = $pData->X(int($nData/3)); $PrevX2 = $pData->X(int($nData/2)); $PrevX3 = $pData->X(int($nData*2/3)); } my $csv = new CSV; $csv->Save($path, \@LabelNameArray, \@DataArray); return 1; } sub ClearAllData { my ($this) = @_; @{$this->{DataArray}} = (); } sub AddGraphData { my ($this, $pXDataArray, $pYDataArray, $LineWidth, $LineColor, $SymbolType, $SymbolSize, $SymbolFillColor, $SymbolLineWidth, $SymbolLineColor, $Option, $XName, $YName) = @_; return if(!$pXDataArray or !$pYDataArray); $this->{PlotMode} = "Graph"; my $IsAutoColor = 0; if($LineColor =~ /^auto$/i) { $LineColor = GraphFrame::GetColor($CurColor); $IsAutoColor = 1; } if($SymbolFillColor =~ /^auto$/i) { $SymbolFillColor = GraphFrame::GetColor($CurColor); $IsAutoColor = 1; } if($SymbolLineColor =~ /^auto$/i) { $SymbolLineColor = GraphFrame::GetColor($CurColor); $IsAutoColor = 1; } $CurColor++ if($IsAutoColor); # $LineColor = 'black' unless($LineColor); # $SymbolFillColor = 'black' unless($SymbolFillColor); # $SymbolLineColor = 'black' unless($SymbolLineColor); $Option = '' unless($Option); my $data = new PlotData; $data->SetXName($XName) if(defined $XName); $data->SetYName($YName) if(defined $YName); $data->SetPlotData($pXDataArray, $pYDataArray, $LineWidth, $LineColor, $SymbolType, $SymbolSize, $SymbolFillColor, $SymbolLineWidth, $SymbolLineColor, $Option); my $pDataArray = $this->{'DataArray'}; push(@$pDataArray, $data); return scalar @$pDataArray; } sub AddDiffractionData { my ($this, $pX, $pY, $pI, $pTag, $pCallBackHoverItem, $SymbolType1, $SymbolSize1, $SymbolColor1, $SymbolType2, $SymbolSize2, $SymbolColor2, $XName, $YName) = @_; return if(!$pX or !$pY); $this->{PlotMode} = "Diffraction"; $this->{pCallBackHoverItem} = $pCallBackHoverItem; my $data = new PlotData; $data->SetXName($XName) if(defined $XName); $data->SetYName($YName) if(defined $YName); $data->SetDiffractionData($pX, $pY, $pI, $pTag, $SymbolType1, $SymbolSize1, $SymbolColor1, $SymbolType2, $SymbolSize2, $SymbolColor2, ''); my $pDataArray = $this->{DataArray}; push(@$pDataArray, $data); return scalar @$pDataArray; } sub CalXMinMax { my ($this) = @_; my $pDataArray = $this->{'DataArray'}; unless($pDataArray) { print "Error in CalXMinMax: pDataArray is not defined\n"; return undef; } my $nData = scalar @$pDataArray; return (0, 0) if($nData <= 0); my ($min, $max) = $pDataArray->[0]->GetXMinMax(); #print "X: $min, $max\n"; for(my $i = 1 ; $i < $nData ; $i++) { my ($min0, $max0) = $pDataArray->[$i]->GetXMinMax(); $min = $min0 if(defined $min0 and $min > $min0); $max = $max0 if(defined $max0 and $max < $max0); } $this->{'XMin'} = $min; $this->{'XMax'} = $max; #print "XMinMax: $min, $max\n"; return ($min, $max); } sub CalYMinMax { my ($this) = @_; my $pDataArray = $this->{DataArray}; return unless($pDataArray); my $nData = scalar @$pDataArray; return (0, 0) if($nData <= 0); my ($min, $max) = $pDataArray->[0]->GetYMinMax(); for(my $i = 1 ; $i < $nData ; $i++) { my ($min0, $max0) = $pDataArray->[$i]->GetYMinMax(); next unless($max0); $min = $min0 if(defined $min0 and $min > $min0); $max = $max0 if(defined $max0 and $max < $max0); } $this->{YMin} = $min; $this->{YMax} = $max; #print "YMinMax: $min, $max [nData=$nData]\n"; return ($min, $max); } sub CalMinMax { my ($this) = @_; my ($xmin, $xmax) = $this->CalXMinMax(); my ($ymin, $ymax) = $this->CalYMinMax(); #print "min,max: $xmin, $xmax y: $ymin, $ymax\n"; } sub CalAdjustViewRange { my ($this, $marginx0, $marginx1, $marginy0, $marginy1, $DoSynchronizeX, $DoSynchronizeY) = @_; $marginx0 = (defined $this->{MarginX0})? $this->{MarginX0} : 0.0 unless(defined $marginx0); $marginx1 = (defined $this->{MarginX1})? $this->{MarginX1} : 0.0 unless(defined $marginx1); $marginy0 = (defined $this->{MarginY0})? $this->{MarginY0} : $marginx0 unless(defined $marginy0); $marginy1 = (defined $this->{MarginY1})? $this->{MarginY1} : $marginx1 unless(defined $marginy1); ($this->{MarginX0}, $this->{MarginX1}, $this->{MarginY0}, $this->{MarginY1}, ) = ($marginx0, $marginx1, $marginy0, $marginy1); #print "PlotType: $this->{XScalePlotType}, $this->{XScalePlotType}\n"; #print "Margin: ($marginx0,$marginy0)-($marginx1,$marginy1)\n"; my $xf = $this->{XFunc}; my $yf = $this->{YFunc}; my $ixf = $this->{XIFunc}; my $iyf = $this->{YIFunc}; my $xa = $this->{XAbs}; my $ya = $this->{YAbs}; my ($xmin, $ymin, $xmax, $ymax) = $this->XYRange(1); my ($xmmin, $ymmin, $xmmax, $ymmax) = $this->CalMaxMarginRange($marginx0, $marginx1, $marginy0, $marginy1); #print "Adj0: xminmax: ($xmin,$ymin)-($xmax,$ymax)\n"; if(1) { if($xmin >= 0.0 and $xmmin < 0.0) { $xmin = 0.0; } else { $xmin = $xmmin; } if($xmax <= 0.0 and $xmmax > 0.0) { $xmax = 0.0; } else { $xmax = $xmmax; } if($ymin >= 0.0 and $ymmin < 0.0) { $ymin = 0.0; } else { $ymin = $ymmin; } if($ymax <= 0.0 and $ymmax > 0.0) { $ymax = 0.0; } else { $ymax = $ymmax; } } if(0) { unless($this->{XScalePlotType} =~ /(log|ln)/) { my $dx = abs($xmax - $xmin); if($xmin > 0 and $dx > 0 and $xmin / $dx < $marginx0) { $xmin = 0.0; } if($xmax < 0 and $dx > 0 and abs($xmax / $dx) < $marginx0) { $xmax = 0.0; } } unless($this->{YScalePlotType} =~ /(log|ln)/) { my $dy = abs($ymax - $ymin); if($ymin > 0 and $dy > 0 and $ymin / $dy < $marginy0) { $ymin = 0.0; } if($ymax < 0 and $dy > 0 and abs($ymax / $dy) < $marginy0) { $ymax = 0.0; } } } $xmin = &$ixf($xmin); $ymin = &$iyf($ymin); $xmax = &$ixf($xmax); $ymax = &$iyf($ymax); ($xmin, $xmax) = Utils::Sort($xmin, $xmax); ($ymin, $ymax) = Utils::Sort($ymin, $ymax); ($xmin, $xmax) = (-$xmax, -$xmin) if($this->{FlipX}); ($ymin, $ymax) = (-$ymax, -$ymin) if($this->{FlipY}); #print "range: ($xmin,$ymin)-($xmax,$ymax)\n"; if($xmin == $xmax) { my $v = $xmin; $v = 1.0 if($v == 0.0); $xmin -= $v / 2.0; $xmax -= $v / 2.0; } if($ymin == $ymax) { my $v = $ymin; $v = 1.0 if($v == 0.0); $ymin -= $v / 2.0; $ymax -= $v / 2.0; } #print "Adj1: ($xmin,$ymin)-($xmax,$ymax)\n"; unless($this->{XScalePlotType} =~ /(log|ln)/) { $xmin = $this->{XMin} if($xmin == 0.0); $xmax = $this->{XMax} if($xmax == 0.0); } unless($this->{YScalePlotType} =~ /(log|ln)/) { $ymin = $this->{YMin} if($ymin == 0.0); $ymax = $this->{YMax} if($ymax == 0.0); } #変換関数がabs()をとるとき if($xa) { if(defined $this->{XMin} and $this->{XMin} * $this->{XMax} < 0.0) { # $xmin = $this->{XMin}; $xmin = &$ixf(&$xf(0.0)); } } if($ya) { if(defined $this->{YMin} and $this->{YMin} * $this->{YMax} < 0.0) { # $ymin = $this->{YMin}; $ymin = &$iyf(&$yf(0.0)); } } #print "Adj2: ($xmin,$ymin)-($xmax,$ymax)\n"; return ($xmin, $ymin, $xmax, $ymax); } sub AdjustViewRange { my ($this, $marginx0, $marginx1, $marginy0, $marginy1, $DoSynchronizeX, $DoSynchronizeY) = @_; return $this->SetViewRange($this->CalAdjustViewRange($marginx0, $marginx1, $marginy0, $marginy1, $DoSynchronizeX, $DoSynchronizeY)); } sub SetCanvasSize { my ($this, $width, $height) = @_; $this->{'CanvasWidth'} = $width; $this->{'CanvasHeight'} = $height; my $rx0 = $this->{'rx0'}; my $ry0 = $this->{'ry0'}; my $rx1 = $this->{'rx1'}; my $ry1 = $this->{'ry1'}; if(defined $rx0) { my $x0 = $rx0 * $width; my $x1 = $rx1 * $width; my $y0 = $ry0 * $height; my $y1 = $ry1 * $height; return $this->SetPosition($x0, $y0, $x1, $y1); } } sub SetScaleStringVisible { my ($this, $XYStr, $f) = @_; if($XYStr =~ /^x/i) { my $scale = $this->GetXScale(); $scale->SetScaleStringVisible($f); } else { my $scale = $this->GetYScale(); $scale->SetScaleStringVisible($f); } } sub SetScaleVisible { my ($this, $XYStr, $f) = @_; if($XYStr =~ /^x/i) { my $scale = $this->GetXScale(); $scale->SetScaleVisible($f); } else { my $scale = $this->GetYScale(); $scale->SetScaleVisible($f); } } sub GetXScale { my ($this, $idx) = @_; $idx = 0 unless(defined $idx); my $pScaleArray = $this->{'GraphScaleArray'}; return unless(defined $pScaleArray); my $c = 0; for(my $i = 0 ; $i < @$pScaleArray ; $i++) { my $scale = $pScaleArray->[$i]; next unless($scale->IsXScale()); return $scale if($c == $idx); $c++; } } sub GetYScale { my ($this, $idx) = @_; $idx = 0 unless(defined $idx); my $pScaleArray = $this->{'GraphScaleArray'}; return unless(defined $pScaleArray); my $c = 0; for(my $i = 0 ; $i < @$pScaleArray ; $i++) { my $scale = $pScaleArray->[$i]; next unless($scale->IsYScale()); return $scale if($c == $idx); $c++; } } sub SetXCaption { my ($this, $caption) = @_; return $this->{'XCaption'} = $caption; } sub SetYCaption { my ($this, $caption) = @_; return $this->{'YCaption'} = $caption; } sub SetFont { my ($this, $pFont) = @_; $this->{'pFont'} = $pFont; my $pScaleArray = $this->{'GraphScaleArray'}; for(my $i = 0 ; $i < @$pScaleArray ; $i++) { my $scale = $pScaleArray->[$i]; $scale->SetFont($pFont); } return $pFont } sub SetXScalePlotType { my ($this, $type, $DoSynchronize) = @_; GraphFrame::SetScalePlotType($this, 'X', $type); my $pScaleArray = $this->{'GraphScaleArray'}; # return unless($pScaleArray); for(my $i = 0 ; $i < @$pScaleArray ; $i++) { my $scale = $pScaleArray->[$i]; next unless($scale->ScalePosition() =~ /^x/i); SetScalePlotType($scale, '', $type); } my $pSXArray = $this->{'XSynchronousGraphFrameArray'}; if($DoSynchronize and $pSXArray) { for(my $i = 0 ; $i < @$pSXArray ; $i++) { my $GraphFrame = $pSXArray->[$i]; $GraphFrame->SetXScalePlotType($type, 0); } } } sub SetYScalePlotType { my ($this, $type, $DoSynchronize) = @_; SetScalePlotType($this, 'Y', $type); my $pScaleArray = $this->{'GraphScaleArray'}; # return unless($pScaleArray); for(my $i = 0 ; $i < @$pScaleArray ; $i++) { my $scale = $pScaleArray->[$i]; next unless($scale->ScalePosition() =~ /^y/i); SetScalePlotType($scale, '', $type); } my $pSYArray = $this->{'YSynchronousGraphFrameArray'}; if($DoSynchronize and $pSYArray) { for(my $i = 0 ; $i < @$pSYArray ; $i++) { my $GraphFrame = $pSYArray->[$i]; $GraphFrame->SetYScalePlotType($type, 0); } } } sub PositionToValue { my ($this, $cx, $cy) = @_; my $xf = $this->{"XFunc"}; my $yf = $this->{"YFunc"}; my $ixf = $this->{"XIFunc"}; my $iyf = $this->{"YIFunc"}; my $xs = $this->{"XSwap"}; my $ys = $this->{"YSwap"}; # $cx = &$xf($cx); # $cy = &$xf($cy); my $x0 = $this->{'x0'}; my $y0 = $this->{'y0'}; my $x1 = $this->{'x1'}; my $y1 = $this->{'y1'}; return unless($y1); my $vx0 = &$xf($this->{'ViewX0'}); my $vy0 = &$yf($this->{'ViewY0'}); my $vx1 = &$xf($this->{'ViewX1'}); my $vy1 = &$yf($this->{'ViewY1'}); ($vx1, $vx0) = ($vx0, $vx1) if($xs); ($vy1, $vy0) = ($vy0, $vy1) if($ys); my $vx = $vx0 + ($vx1 - $vx0) / ($x1 - $x0) * ($cx - $x0); my $vy = $vy0 + ($vy1 - $vy0) / ($y1 - $y0) * ($cy - $y0); return (&$ixf($vx), &$iyf($vy)); } sub ValueToPosition { my ($this, $vx, $vy) = @_; $vx = 0.0 if(!defined $vx); # or $vx eq ''); $vy = 0.0 if(!defined $vy); # or $vy eq ''); my $xf = $this->{"XFunc"}; my $yf = $this->{"YFunc"}; my $xs = $this->{"XSwap"}; my $ys = $this->{"YSwap"}; $vx = &$xf($vx); $vy = &$yf($vy); my $x0 = $this->{'x0'}; my $y0 = $this->{'y0'}; my $x1 = $this->{'x1'}; my $y1 = $this->{'y1'}; my $vx0 = &$xf($this->{'ViewX0'}); my $vy0 = &$yf($this->{'ViewY0'}); my $vx1 = &$xf($this->{'ViewX1'}); my $vy1 = &$yf($this->{'ViewY1'}); ($vx1, $vx0) = ($vx0, $vx1) if($xs); ($vy1, $vy0) = ($vy0, $vy1) if($ys); #print "xy: ($vx,$vy) cxy: ($vx0,$vy0)-($vx1,$vy1)\n"; # $vx1 = $vx0 + 1.0 if($vx0 == $vx1); # $vy1 = $vy0 + 1.0 if($vy0 == $vy1); my $x = $x0 + ($x1 - $x0) / ($vx1 - $vx0) * ($vx - $vx0); my $y = $y0 + ($y1 - $y0) / ($vy1 - $vy0) * ($vy - $vy0); return ($x, $y); } sub XVal { my ($this, $v) = @_; my $xf = $this->{"XFunc"}; return &$xf($v); } sub YVal { my ($this, $v) = @_; my $yf = $this->{"YFunc"}; return &$yf($v); } sub CheckGraphFrameSize { my ($this) = @_; #print "this=$this\n"; my $x0 = $this->{'x0'}; my $y0 = $this->{'y0'}; my $x1 = $this->{'x1'}; my $y1 = $this->{'y1'}; #print "X: $x0:$y0:$x1:$y1\n"; $x1 = $x0 + 1.0 if($x0 == $x1); $y1 = $y0 + 1.0 if($y0 == $y1); $this->SetPosition($x0, $y0, $x1, $y1); my $vx0 = $this->{'ViewX0'}; my $vy0 = $this->{'ViewY0'}; my $vx1 = $this->{'ViewX1'}; my $vy1 = $this->{'ViewY1'}; $vx1 = $vx0 + 1.0 if($vx0 == $vx1); $vy1 = $vy0 + 1.0 if($vy0 == $vy1); $this->SetViewRange($vx0+0.0, $vy0+0.0, $vx1+0.0, $vy1+0.0); } sub Draw { my ($this, $canvas) = @_; $canvas = $this->Canvas() unless($canvas); $canvas->SetClipRect($this->{'rtClip'}); $canvas->SetSmoothLine(0); my $idx = $this->Index(); my $xf = $this->{"XFunc"}; my $yf = $this->{"YFunc"}; #print "xf=$xf\n"; #print "yf=$yf\n"; my $rect = new Rect; $this->CheckGraphFrameSize(); my $x0 = $this->{'x0'}; my $y0 = $this->{'y0'}; my $x1 = $this->{'x1'}; my $y1 = $this->{'y1'}; my $vx0 = $this->{'ViewX0'}; my $vy0 = $this->{'ViewY0'}; my $vx1 = $this->{'ViewX1'}; my $vy1 = $this->{'ViewY1'}; #print "ViewRange: ($vx0,$vy0)-($vx1,$vy1)\n"; $this->{'GraphScaleX'}->SetCaption($this->{'XCaption'}); $this->{'GraphScaleY'}->SetCaption($this->{'YCaption'}); my $font = $canvas->CreateFont("times", 16, "normal"); $font = $this->{'pFont'} if($this->{'pFont'}); #GraphFrameの描画 $canvas->DrawBox($x0, $y0, $x1, $y1, 2, 'white', 'white', "Frame$idx"); $canvas->lower("Frame$idx"); $canvas->DrawLine($x0, $y0, $x1, $y0, 2, 'black', "Frame$idx") if($this->BottomLineVisible()); $canvas->DrawLine($x1, $y0, $x1, $y1, 2, 'black', "Frame$idx") if($this->RightLineVisible()); $canvas->DrawLine($x1, $y1, $x0, $y1, 2, 'black', "Frame$idx") if($this->TopLineVisible()); $canvas->DrawLine($x0, $y1, $x0, $y0, 2, 'black', "Frame$idx") if($this->LeftLineVisible()); #print "Frame: $x0, $y0, $x1, $y1\n"; $rect->Merge($x0, $y0, $x1, $y1); #X=0 赤線の描画 my ($xc, $yc) = $this->ValueToPosition(0.0, 0.0); if($vx0 < 0 and 0 < $vx1) { #print "vx0-1: $vx0 - $vx1\n"; #print "Plot X=0 Vis=", $this->X0LineVisible(), "\n"; $canvas->DrawLine($xc, $y0, $xc, $y1, 1, 'red') if($this->X0LineVisible()); } #Y=0 赤線の描画 if($vy0 < 0 and 0 < $vy1) { #print "vy0-1: $vy0 - $vy1\n"; #print "Plot Y=0 Vis=", $this->Y0LineVisible(), "\n"; $canvas->DrawLine($x0, $yc, $x1, $yc, 1, 'red') if($this->Y0LineVisible()); } #目盛りの描画 my $pScaleArray = $this->{'GraphScaleArray'}; for(my $i = 0 ; $i < @$pScaleArray ; $i++) { my $scale = $pScaleArray->[$i]; $rect->Merge($scale->Draw($canvas)); } my $PlotMode = 0; $PlotMode = 1 if(defined $this->{PlotMode} and $this->{PlotMode} eq "Diffraction"); $canvas->SetSmoothLine($this->SmoothLine()); my %TagHash; for(my $iData = 0 ; $iData < $this->GetnGraphData() ; $iData++ ) { my $pData = $this->{'DataArray'}->[$iData]; next unless($pData->Visible()); my $Tag = "Data-$iData-" . $this->Index(); my $YName = $pData->GetYName(); $YName = $Tag unless($YName); $TagHash{$Tag} = $YName; my $pXArray = $pData->GetXArrayRef(); my $pYArray = $pData->GetYArrayRef(); my $pIArray = $pData->GetIArrayRef(); my $pTagArray = $pData->GetTagArrayRef(); my $nData = scalar @$pXArray; my $Line = $pData->GetLine(); my $Symbol = $pData->GetSymbol(); my $Symbol2 = $pData->GetSymbol2(); my $LineWidth = $Line->Width(); my $SymbolType = $Symbol->Type(); my $Option = $pData->GetOption(); my $XSkip = 0; $XSkip = 1 if($Option =~ /XAutoSkip/i); my $nViewData = 0; for(my $i = 0 ; $i < $nData ; $i++) { my $vx = $pXArray->[$i]; my $vy = $pYArray->[$i]; next if(!defined $vx or !defined $vy); # or $vx eq '' or $vy eq ''); #print "vx=$vx ($vx0-$vx1) / vy=$vy ($vy0-$vy1)\n"; next if($vx < $vx0 or $vx1 < $vx or $vy < $vy0 or $vy1 < $vy); $nViewData++; } my $iSkip = 1; # if($Option =~ /XAutoSkip/i) { # $iSkip = int($nViewData / ($x1 - $x0) * 0.33); # } # $iSkip = 1 if($iSkip < 1); if(defined $LineWidth and $LineWidth > 0) { my $LineColor = $Line->Color(); $canvas->PrepareDrawLines($LineWidth, $LineColor, $Tag); my ($xp, $yp); for(my $i = 0 ; $i < $nData ; $i += $iSkip) { my $vx = $pXArray->[$i]; my $vy = $pYArray->[$i]; next unless(defined $vy); my ($x, $y) = $this->ValueToPosition($vx, $vy); if($XSkip and $i > 0) { my $dx = $x - $xp; my $dy = $y - $yp; my $r2 = $dx*$dx + $dy*$dy; next if($r2 < 8); } if($i > 0) { $canvas->DrawClippedLine($xp, $yp, $x, $y, $LineWidth, $LineColor, $Tag); } $xp = $x; $yp = $y; } $canvas->DrawPushedLines(); } elsif($SymbolType ne '') { my ($xp, $yp); for(my $i = 0 ; $i < $nData ; $i += $iSkip) { my $vx = $pXArray->[$i]; my $vy = $pYArray->[$i]; my ($x, $y) = $this->ValueToPosition($vx, $vy); if($XSkip and $i > 0) { my $dx = $x - $xp; my $dy = $y - $yp; my $r2 = $dx*$dx + $dy*$dy; next if($r2 < 8); } if($this->IsInside($x, $y)) { if($PlotMode == 1) { # Diffraction #print "D, t=$pTagArray->[$i]\n"; my $iTag = "${Tag}-$i"; my $I = $pIArray->[$i]; $I = 1.0e-5 if($I < 1.0e-5); my $symbol = new Symbol; # if($I == 0.0) { if($I < 1.0e-3) { #print "c=$Symbol2->{Type}, $Symbol2->{Size}, $Symbol2->{FillColor}, $Symbol2->{LineWidth}, $Symbol2->{LineColor})\n"; $symbol->SetStyle($Symbol2->{Type}, $Symbol2->{Size}, $Symbol2->{FillColor}, $Symbol2->{LineWidth}, $Symbol2->{LineColor}); $symbol->Draw($canvas, $x, $y, $iTag, $I) if($Symbol2->{Size} > 0); } else { my $size = int($Symbol->{Size} * log($I) / log(1000.0)); $size = 1 if($size < 1); $symbol->SetStyle($Symbol->{Type}, $size, $Symbol->{FillColor}, $Symbol->{LineWidth}, $Symbol->{LineColor}); $symbol->Draw($canvas, $x, $y, $iTag, $I) if($Symbol->{Size} > 0); } $TagHash{$iTag} = $pTagArray->[$i]; my $pFunc = $this->{pCallBackHoverItem}; if($pFunc) { my %pDataInf; $pDataInf{index} = $i; $pDataInf{vx} = $vx; $pDataInf{vy} = $vy; $pDataInf{vz} = $I; $pDataInf{x} = $x; $pDataInf{y} = $y; $pDataInf{Tag} = $pTagArray->[$i]; $canvas->bind($iTag, "", sub { &$pFunc("Enter", \%pDataInf); }); $canvas->bind($iTag, "", sub { &$pFunc("Leave", \%pDataInf); }); } } else { $Symbol->Draw($canvas, $x, $y, $Tag); } } $xp = $x; $yp = $y; } } } $this->mw()->Balloon()->attach($canvas, -balloonposition => 'mouse', -msg => \%TagHash); $canvas->SetSmoothLine(0); return $rect; } sub SetViewXRange { my ($this, $x0, $x1, $DoSynchronize) = @_; $x0 = $this->{ViewX0} if(!defined $x0); $x1 = $this->{ViewX1} if(!defined $x1); $x0 = $this->{XMin} if(!defined $x0); $x1 = $this->{XMax} if(!defined $x1); $DoSynchronize = $this->{DoSynchonizeX} if(!defined $DoSynchronize); $this->{DoSynchonizeX} = $DoSynchronize; $this->{ViewX0} = $x0; $this->{ViewX1} = $x1; my $pScaleArray = $this->{GraphScaleArray}; for(my $i = 0 ; $i < @$pScaleArray ; $i++) { my $scale = $pScaleArray->[$i]; #print "SP: ", $scale->ScalePosition(), "\n"; #print "i=$i x0=$x0 x1=$x1\n"; next unless($scale->ScalePosition() =~ /^x/i); $scale->SetViewXRange($x0, $x1); } my $pSXArray = $this->{XSynchronousGraphFrameArray}; #print("Dos: $DoSynchronize and $pSXArray\n"); if($DoSynchronize and $pSXArray) { for(my $i = 0 ; $i < @$pSXArray ; $i++) { my $GraphFrame = $pSXArray->[$i]; #print("i=$i: $GraphFrame ($x0,$x1)\n"); $GraphFrame->SetViewXRange($x0+0.0, $x1+0.0, 0); } } } sub SetViewYRange { my ($this, $y0, $y1, $DoSynchronize) = @_; $y0 = $this->{ViewY0} if(!defined $y0); $y1 = $this->{ViewY1} if(!defined $y1); $y0 = $this->{YMin} if(!defined $y0); $y1 = $this->{YMax} if(!defined $y1); $DoSynchronize = $this->{DoSynchonizeY} if(!defined $DoSynchronize); $this->{DoSynchonizeY} = $DoSynchronize; $this->{'ViewY0'} = $y0; $this->{'ViewY1'} = $y1; my $pScaleArray = $this->{'GraphScaleArray'}; for(my $i = 0 ; $i < @$pScaleArray ; $i++) { my $scale = $pScaleArray->[$i]; next unless($scale->ScalePosition() =~ /^y/i); $scale->SetViewYRange($y0, $y1); } my $pSYArray = $this->{'YSynchronousGraphFrameArray'}; if($DoSynchronize and $pSYArray) { for(my $i = 0 ; $i < @$pSYArray ; $i++) { my $GraphFrame = $pSYArray->[$i]; $GraphFrame->SetViewYRange($y0+0.0, $y1+0.0, 0); } } } sub SetViewRange { my ($this, $x0, $y0, $x1, $y1, $DoSynchronizeX, $DoSynchronizeY) = @_; $x0 = $this->{ViewX0} if(!defined $x0); $x1 = $this->{ViewX1} if(!defined $x1); $y0 = $this->{ViewY0} if(!defined $y0); $y1 = $this->{ViewY1} if(!defined $y1); $x0 = $this->{XMin} if(!defined $x0); $x1 = $this->{XMax} if(!defined $x1); $y0 = $this->{YMin} if(!defined $y0); $y1 = $this->{YMax} if(!defined $y1); $x0 = 0.0 if(!defined $x0); $y0 = 1.0 if(!defined $y0); $x1 = 0.0 if(!defined $x1); $y1 = 1.0 if(!defined $y1); #print "DoSynchronizeX=$DoSynchronizeX\n"; $this->SetViewXRange($x0, $x1, $DoSynchronizeX); $this->SetViewYRange($y0, $y1, $DoSynchronizeY); return ($x0, $y0, $x1, $y1); } sub RecalcScale { my ($this) = @_; my $pScaleArray = $this->{'GraphScaleArray'}; my ($x0, $x1) = $this->GetViewXRange(); my ($y0, $y1) = $this->GetViewYRange(); for(my $i = 0 ; $i < @$pScaleArray ; $i++) { my $scale = $pScaleArray->[$i]; $scale->SetViewRange($x0, $y0, $x1, $y1); } } sub SetPosition { my ($this, $x0, $y0, $x1, $y1) = @_; #print "x: $x0, $y0, $x1, $y1\n"; $x0 = int($x0); $y0 = int($y0); $x1 = int($x1); $y1 = int($y1); $this->{'x0'} = $x0; $this->{'y0'} = $y0; $this->{'x1'} = $x1; $this->{'y1'} = $y1; #print "S $x0 $y0 $x1 $y1\n"; $this->{'rtPosition'} = new Rect($x0, $y0, $x1, $y1); $this->{'rtClip'} = new Rect($x0, $y0, $x1, $y1); my $pScaleArray = $this->{'GraphScaleArray'}; for(my $i = 0 ; $i < @$pScaleArray ; $i++) { my $scale = $pScaleArray->[$i]; $scale->SetPosition($x0, $y0, $x1, $y1); } } sub SetPositionByRatio { my ($this, $rx0, $ry0, $rx1, $ry1) = @_; $this->{'rx0'} = $rx0; $this->{'ry0'} = $ry0; $this->{'rx1'} = $rx1; $this->{'ry1'} = $ry1; #print "S $rx0 $ry0 $rx1 $ry1\n"; my $w = $this->CanvasWidth(); my $h = $this->CanvasHeight(); #print "S h=$h w=$w\n"; if(defined $w) { my $x0 = int($rx0 * $w); my $x1 = int($rx1 * $w); my $y0 = int($ry0 * $h); my $y1 = int($ry1 * $h); return $this->SetPosition($x0, $y0, $x1, $y1); } } sub SetPositionByStr { my ($this, $str) = @_; #print "SetPositionByStr: $str\n"; if($str =~ /^r(.*)$/) { $str = $1; my ($rx0, $ry0, $rx1, $ry1) = ($str =~ /^\s*([\d\.+-]+)\s*,\s*([\d\.+-]+)\s*,\s*([\d\.+-]+)\s*,\s*([\d\.+-]+)/); $this->SetPositionByRatio($rx0, $ry0, $rx1, $ry1); } else { my ($x0, $y0, $x1, $y1) = ($str =~ /^(\d+),(\d+),(\d+),(\d+)/); $this->SetPosition($x0, $y0, $x1, $y1); } } sub AddSynchronousFrame { my ($this, $XorY, $GraphFrame) = @_; if($XorY =~ /x/i) { my $pSXArray = $this->{'XSynchronousGraphFrameArray'}; push(@$pSXArray, $GraphFrame); $this->{DoSynchonizeX} = 1; } else { my $pSYArray = $this->{'YSynchronousGraphFrameArray'}; push(@$pSYArray, $GraphFrame); $this->{DoSynchonizeX} = 1; } } sub IsPointInFrame { my ($this, $x, $y) = @_; return 0 unless(defined $y); my ($x0, $y0, $x1, $y1) = $this->GetPosition(); return 0 unless(defined $y1); my $rx = ($x - $x0) / ($x1 - $x0); return 0 if($rx > 1.0 or $rx < 0.0); my $ry = ($y - $y0) / ($y1 - $y0); return 0 if($ry > 1.0 or $ry < 0.0); return 1; } #============================================================ # ダイアログ関数 #============================================================ sub ShowScaleDialog { my ($this, $title, $x0, $y0, $x1, $y1, $XPlotType, $YPlotType, $SyncXScalePlotType, $SyncYScalePlotType, $DoRedraw) = @_; $SyncXScalePlotType = 1 unless(defined $SyncXScalePlotType); $SyncYScalePlotType = 1 unless(defined $SyncYScalePlotType); $DoRedraw = 1 unless(defined $DoRedraw); my $mw = $this->MainWindow(); $x0 = $this->{'ViewX0'} unless(defined $x0); $y0 = $this->{'ViewY0'} unless(defined $y0); $x1 = $this->{'ViewX1'} unless(defined $x1); $y1 = $this->{'ViewY1'} unless(defined $y1); $x0 = Utils::Round($x0, 4, 1); $y0 = Utils::Round($y0, 4, 1); $x1 = Utils::Round($x1, 4, 1); $y1 = Utils::Round($y1, 4, 1); $XPlotType = $this->XScalePlotType() unless(defined $XPlotType); $YPlotType = $this->YScalePlotType() unless(defined $YPlotType); my $PlotXZero = $this->X0LineVisible(); my $PlotYZero = $this->Y0LineVisible(); ($x0, $x1, $y0, $y1, $XPlotType, $YPlotType, $PlotXZero, $PlotYZero) = Dialog::ShowScaleDialog($mw, $title, $x0, $x1, $y0, $y1, $XPlotType, $YPlotType, $PlotXZero, $PlotYZero); $this->SetX0LineVisible($PlotXZero); $this->SetY0LineVisible($PlotYZero); #print "D: [$x0][$x1]\n"; return unless(defined $x0); $this->SetXScalePlotType($XPlotType, $SyncXScalePlotType); $this->SetYScalePlotType($YPlotType, $SyncYScalePlotType); $this->SetViewRange($x0+0.0, $y0+0.0, $x1+0.0, $y1+0.0, 1); $this->mw()->Redraw() if($DoRedraw); } sub ShowGraphFrameDialog { my ($this, $title) = @_; my $mw = $this->MainWindow(); my ($x0, $y0, $x1, $y1) = Dialog::SetupBoxDialog($mw, $title, 5, "(x0,y0) = (", $this->{'x0'}, ", ", $this->{'y0'}, ")", "(x1,y1) = (", $this->{'x1'}, ", ", $this->{'y1'}, ")" ); #print "x=$x0,$y0,$x1,$y1\n"; return unless(defined $x0); #$App側ではグラフ枠サイズの更新を見地できないため、ここでグラフ枠サイズの変更をしておく $this->SetPosition($x0, $y0, $x1, $y1); #Redraw時に新しいサイズを反映するように、グラフ枠サイズの$App変数を更新。 $mw->UpdateGraphFramePosition(); $mw->Redraw(); } 1;