#=============================================== # TkOpticalDataConvert #=============================================== package TkOpticalDataConvert; use clib::TkFittingCommon; @ISA = qw(TkFittingCommon); #公開したいサブルーチン #@EXPORT = qw(DelSpace Reduce01 MakePath RegExpQuote); use strict; use Math::Spline; use Utils; use IniFile; use CSV; use MultiColumnData; use MyTk::GraphFrameArray; use Sci::Science; use Sci::Algorism; use Sci::Optimize; #============================================================ # 変数等取得関数 #============================================================ #============================================================ # コンストラクタ、デストラクタ #============================================================ #呼び出されることはない sub new { my ($module, $app) = @_; my $this = {}; bless $this; return $this; } sub DESTROY { my $this = shift; $this->SUPER::DESTROY(@_); } #============================================================ # 継承クラスで定義しなおす関数 #============================================================ sub CreateLeftFrame { my ($this, $ConfigSide, @args) = @_; # return $this->SUPER::CreateLeftFrame(); return undef; } sub CreateSelectFilePane { my ($this) = @_; # return $this->SUPER::CreateSelectFilePane(); return undef; } sub CreateFileContentPane { return undef; } sub CreateWidgets { my ($this, $DoSuperOnly) = @_; $DoSuperOnly = 0 if(!defined $DoSuperOnly); my $App = $this->App(); my $args = $App->Args(); my $mw = $this->mw(); my $Program = "OpticalDataConverter2007"; $this->{ini} = new IniFile; $this->{TransmittanceDataFile} = new MultiColumnData; $this->{ReflectanceDataFile} = new MultiColumnData; $this->SUPER::CreateWidgets(); return if($DoSuperOnly); $mw->SetTitle("$Program / TkPlot"); $this->App()->SetProgram("$Program / TkPlot"); #=================================================== # ペインを作製 #=================================================== my $EntryWidth = 12; my $Frame = $mw->MyLabFrame( -label => 'Transmittance', -labelside => 'acrosstop', )->pack(-anchor => 'nw', -fill => 'x'); my $Frame1 = $Frame->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->MakeChooseFileEntry($Frame1, 'TransmittanceCSV', 'T:', $this->{ini}->pVariable("TransmittanceCSVFile", ""), '&Choose', sub { $this->ChooseFile(@_); }, "ChooseTransmittanceFile"); $this->{EditDataButton} = $Frame1->MyButton( -text => 'ed', -takefocus => 1, -command => sub { $this->ButtonPressed('RButtonDown', 'EditTransmittanceCSV'); }, )->pack(-side => 'left'); $Frame1 = $Frame->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->{ChooseTransmittanceXListBox} = $Frame1->MyBrowseEntry( -label => "X:", -state => "readonly", -takefocus => 1, -width => 5, -Selections => [], -SelIndex => 0, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $this->{ChooseTransmittanceXListBox}->configure( -browsecmd => sub { $this->SelChangeListBox("X", $this->{ChooseTransmittanceXListBox}); } ); $this->{ChooseTransmittanceY1ListBox} = $Frame1->MyBrowseEntry( -label => "Y1:", -state => "readonly", -takefocus => 1, -width => 5, -Selections => [], -SelIndex => 1, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $this->{ChooseTransmittanceY1ListBox}->configure( -browsecmd => sub { $this->SelChangeListBox("Y1", $this->{ChooseTransmittanceY1ListBox}); } ); $Frame = $mw->MyLabFrame( -label => 'Reflectance', -labelside => 'acrosstop', )->pack(-anchor => 'nw', -fill => 'x'); $Frame1 = $Frame->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->MakeChooseFileEntry($Frame1, 'ReflectanceCSV', 'R:', $this->{ini}->pVariable("ReflectanceCSVFile", ""), '&Choose', sub { $this->ChooseFile(@_); }, "ChooseReflectanceFile"); $this->{EditDataButton} = $Frame1->MyButton( -text => 'ed', -takefocus => 1, -command => sub { $this->ButtonPressed('RButtonDown', 'EditReflectanceCSV'); }, )->pack(-side => 'left'); $Frame1 = $Frame->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->{ChooseReflectanceXListBox} = $Frame1->MyBrowseEntry( -label => "X:", -state => "readonly", -takefocus => 1, -width => 5, -Selections => [], -SelIndex => 0, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $this->{ChooseReflectanceXListBox}->configure( -browsecmd => sub { $this->SelChangeListBox("X", $this->{ChooseReflectanceXListBox}); } ); $this->{ChooseReflectanceY1ListBox} = $Frame1->MyBrowseEntry( -label => "Y1:", -state => "readonly", -takefocus => 1, -width => 5, -Selections => [], -SelIndex => 1, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $this->{ChooseReflectanceY1ListBox}->configure( -browsecmd => sub { $this->SelChangeListBox("Y1", $this->{ChooseReflectanceY1ListBox}); } ); $Frame = $mw->MyLabFrame( -label => 'Action', -labelside => 'acrosstop', )->pack(-anchor => 'nw', -fill => 'x'); my $lsb4 = $this->{ChooseActionListBox} = $Frame->MyBrowseEntry( -label => "Action:", -state => "readonly", -takefocus => 1, -width => 10, -Selections => [ # 'InterpolateByMath::Spline', 'InterpolateByCubicSpline', 'InterpolateBy4thPolynomial', 'InterpolateBySimpson', 'InterpolateByLagrange', 'Interpolate', ], -SelIndex => 0, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $lsb4->configure(-browsecmd => sub { $this->SelChangeListBox("Direction", $this->{ChooseActionListBox}); } ); $Frame = $mw->MyLabFrame( -label => 'Output', -labelside => 'acrosstop', )->pack(-anchor => 'nw', -fill => 'x'); $this->MakeLabelEntry($Frame, "X0", "X:", $this->{ini}->pVariable('X0', 0.5), "%g", $EntryWidth, "", 0, 0); $this->MakeLabelEntry($Frame, "X1", "-", $this->{ini}->pVariable('X1', 5.0), "%g", $EntryWidth, "", 0, 1); $this->MakeLabelEntry($Frame, "XStep", ",", $this->{ini}->pVariable('XStep', 0.05), "%g", $EntryWidth, "", 0, 2); $this->UpdateParameters(); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->{RecalcButton} = $Frame->MyButton( -text => '&Recalc', -takefocus => 1, -command => sub { $this->ButtonPressed('RButtonDown', 'Recalc'); }, )->pack(-side => 'left'); $this->{SaveButton} = $Frame->MyButton( -text => '&Save', -takefocus => 1, -command => sub { $this->ButtonPressed('RButtonDown', 'Save'); }, )->pack(-side => 'left'); #ツールバーのOpenボタンをファイル読み込みにバインドする $mw->{OpenButton}->configure( -command => sub { $this->ChooseFile($this->{TransmittancfeCSVEntry}, @_); }, ) if($mw->{OpenButton}); } sub Initialize { my ($this, $InitializeParameterFile, $InitializeData) = @_; # $this->{TransmittanceDataFile} = new MultiColumnData; # $this->{ReflectanceDataFile} = new MultiColumnData; if($InitializeParameterFile) { $this->{ini}->{TransmittanceCSVFile} = ''; $this->{ini}->{ReflectanceCSVFile} = ''; } if($InitializeData) { $this->{pCalX} = undef; $this->{pCalY1} = undef; $this->{pCalY2} = undef; } } sub ChooseFile { my ($this, $type, $widget, $Option) = @_; my $App = $this->App(); my $canvas = $this->Canvas(); my $mw = $this->mw(); #print "type=$type, wid=$widget, Opt=$Option\n"; my $mode = 'open'; my $fmask = '*.csv;*.spe;*.jel;*.asp;*.smo;*isa;*.ref;*.pal;*.bef;*.aft'; if($Option eq 'ChooseParameterFile') { # $mode = 'save'; $fmask = '*.prm'; } my $dir = ''; unless($widget) { $dir = $this->App()->{WorkDir}; chdir($dir); } my $defstr = ''; my $message = 'Choose file'; my $filepath = Dialog::OpenFileDialog($mw, 'open', $fmask, $defstr, $message, $dir); if($filepath) { my $DirPath = $this->SetWorkDir($filepath); if($widget) { $widget->SetText($filepath); } } else { return undef; } my $ret; if($Option eq 'ChooseParameterFile') { $ret = $this->ReadParameterFile($filepath); return undef unless($ret); $this->Draw(); } elsif($type =~ /Transmittance/ or $type =~ /Reflectance/) { $ret = $this->ReadSampleDataFile($filepath, $type); return undef unless($ret); $this->Draw(); } return $ret; } sub SelChangeListBox { my ($this, $type, $lb) = @_; #print "this:$this lb=$lb\n"; my $s = $lb->GetText(); if($type eq 'TransmittanceX' or $type eq 'TransmittanceY1') { } elsif($type eq 'ReflectanceX' or $type eq 'ReflectanceY1') { } $this->AssignGraphData(); $this->Draw(); } sub ButtonPressed { my ($this, $event, $type) = @_; my $App = $this->App(); #print "this=$this\n"; if($type eq 'Recalc') { $this->Recalc(); } elsif($type eq 'Save') { $this->Save(); } elsif($type eq 'SaveParam') { $this->SaveParameterFile($this->{ini}->{ParameterFile}); return; } elsif($type eq 'EditParam') { my $Editor = $this->App()->{EditorPath}; my $File = $this->{ini}->{ParameterFile}; my $command = "$Editor $File"; system($command); return; } elsif($type eq 'EditTransmittanceCSV') { my $Editor = $this->App()->{EditorPath}; my $File = $this->{ini}->{TransmittanceCSVFile}; my $command = "$Editor $File"; system($command); return; } elsif($type eq 'EditReflectanceCSV') { my $Editor = $this->App()->{EditorPath}; my $File = $this->{ini}->{ReflectanceCSVFile}; my $command = "$Editor $File"; system($command); return; } } #=================================================== # データ処理 #=================================================== sub Save { my ($this) = @_; $this->Recalc(0); my $OutFile = $this->{TransmittanceCSVFileEntry}->GetText(); $OutFile = $this->{ReflectanceCSVFileEntry}->GetText() if(!$OutFile); if(!$OutFile) { $this->print("Error: Data source is not specified.\n"); return; } my ($drive, $dir, $filename, $ext, $lastdir, $filebody) = Deps::SplitFilePath($OutFile); $OutFile = Deps::MakePath("$drive$dir", "${filebody}-Interpolated.csv", 0); # $OutFile = Deps::ReplaceExtension($OutFile, "-Interpolated.csv"); my $pE = $this->{CalX}; my $pT = $this->{CalY1}; my $pR = $this->{CalY2}; my @label = ('E(eV)', 'wl(nm)'); my @pData; if($pT) { @label = (@label, 'T'); @pData = (@pData, $pT); } if($pR) { @label = (@label, 'R'); @pData = (@pData, $pR); } my $out = new JFile($OutFile, "w"); if(!$out) { $this->print("Error: Can not write to [$OutFile].\n"); return; } for(my $j = 0 ; $j < @label ; $j++) { if($j == 0) { $out->print("$label[$j]"); } else { $out->print(",$label[$j]"); } } $out->print("\n"); my $n = @$pE; for(my $i = 0 ; $i < $n ; $i++) { my $E = $pE->[$i]; my $wl = Optics::eVTonm($E); $out->print("$E,$wl"); for(my $j = 0 ; $j < @pData ; $j++) { $out->print(",$pData[$j]->[$i]"); } $out->print("\n"); } $out->Close(); $this->print("Data has been saved to [$OutFile].\n"); } sub Recalc { my ($this, $ResetViewRange) = @_; $ResetViewRange = 1 if(!defined $ResetViewRange); $this->{CalX} = undef; $this->{CalY1} = undef; $this->{CalY2} = undef; my $Action = $this->{ChooseActionListBox}->GetText(); my $x0 = $this->{ini}->{X0}; my $x1 = abs($this->{ini}->{X1}); my $xstep = abs($this->{ini}->{XStep}); print "Action: $Action [x=$x0 - $x1, $xstep]\n"; my $func; if($Action eq 'Interpolate') { $func = \&Algorism::Interpolate; } elsif($Action eq 'InterpolateBySimpson') { $func = \&Algorism::InterpolateBySimpson; } elsif($Action eq 'InterpolateBy4thPolynomial') { $func = \&Algorism::InterpolateBy4thPolynomial; } elsif($Action eq 'InterpolateByLagrange') { $func = \&Algorism::InterpolateByLagrange; } elsif($Action eq 'InterpolateByCubicSpline') { $func = \&Algorism::InterpolateByCubicSpline; } elsif($Action eq 'DifferentiateByLagrange') { $func = \&Algorism::DifferentiateByLagrange; } elsif($Action eq 'DifferentiateByCubicSpline') { $func = \&Algorism::DifferentiateByCubicSpline; } else { $this->App()->print("Error in Recalc:: Invalid Action [$Action] #2.\n"); return undef; } my $pSortedT = $this->{TransmittanceDataFile}->SortXYByX(1); my $pSortedR = $this->{ReflectanceDataFile}->SortXYByX(1); my $YLabel = ''; my ($pX1, $pX2, $pY1, $pY2, $nData); if($pSortedT) { $pX1 = $pSortedT->pX(); $pY1 = $pSortedT->pY(); } if($pSortedR) { $pX2 = $pSortedR->pX(); $pY2 = $pSortedR->pY(); } my (@x, @y1, @y2); for(my $i = 0 ; ; $i++) { my $xx = $x0 + $xstep * $i; last if($xx > $x1); my ($yy1, $yy2); $yy1 = &$func($pX1, $pY1, $xx) if($pY1); $yy1 = 0.0 if(!defined $yy1); $yy2 = &$func($pX2, $pY2, $xx) if($pY2); $yy2 = 0.0 if(!defined $yy2); $x[$i] = $xx; $y1[$i] = $yy1; $y2[$i] = $yy2; } $this->{CalX} = \@x; if($pSortedT) { $this->{CalY1} = \@y1; } if($pSortedR) { $this->{CalY2} = \@y2; } $this->AssignGraphData(0); $this->Draw(); } sub ReadSampleDataFile { my ($this, $filepath, $type, $IsPrint) = @_; my $App = $this->App(); $this->Initialize(0, 1); if($type =~ /Transmittance/i) { $type = "Transmittance"; } else { $type = "Reflectance"; } $this->{"${type}Path"} = $filepath; $this->{"${type}DataFile"}->SetSkipBlankData(1); my ($nData, $pLabelArray, @pDataArray) = $this->{"${type}DataFile"}->Read($filepath); #print "type=$type, TransmittanceDataFile\n"; if(!defined $nData) { $App->print("Error: Can not read [$filepath].\n"); return $this->{"${type}Path"} = undef; } my $nDataArray = $this->{"${type}DataFile"}->nDataArray(); #print "nDataArray: $nDataArray\n"; $this->{"Choose${type}XListBox"}->DeleteAllItem(); $this->{"Choose${type}Y1ListBox"}->DeleteAllItem(); for(my $i = 0 ; $i < $nDataArray ; $i++) { #print "$i: $pLabelArray->[$i]\n"; $this->{"Choose${type}XListBox"}->AddItem($pLabelArray->[$i]); $this->{"Choose${type}Y1ListBox"}->AddItem($pLabelArray->[$i]); } $this->{"Choose${type}XListBox"}->SetCurSel('E.*', '.*eV.*', 'wl.*'); if($type eq 'Transmittance') { $this->{"Choose${type}Y1ListBox"}->SetCurSel('T.*', 'y.*'); $this->{"${type}DataFile"}->GetXData('E.*', '.*eV.*', 'wl.*'); $this->{"${type}DataFile"}->GetYData('T.*', 'y.*'); } else { $this->{"Choose${type}Y1ListBox"}->SetCurSel('R.*', 'y.*'); $this->{"${type}DataFile"}->GetXData('E.*', '.*eV.*', 'wl.*'); $this->{"${type}DataFile"}->GetYData('R.*', 'y.*'); } if(0) { ($this->{ini}->{X0}, $this->{ini}->{X1}) = $this->{"${type}DataFile"}->CalMinMax(); my ($minxstep, $maxstep) = $this->{"${type}DataFile"}->CalMinMaxStep(); my $n = 0; if($minxstep > 0.0) { $n = int( abs($this->{ini}->{X1} - $this->{ini}->{X0}) / $minxstep + 1.0001); } if($n > 101 or $minxstep == 0.0) { $minxstep = abs($this->{ini}->{X1} - $this->{ini}->{X0}) / 101; } $this->{ini}->{XStep} = $minxstep; } $this->CreateGraphFrame(); $this->AssignGraphData(); return $filepath; } sub CreateGraphFrame { my ($this, $canvas, $TargetData) = @_; $canvas = $this->Canvas(); my $App = $this->App(); my $font = $App->{'GraphFrameFont'}; my @font = split(/,/, $font) if($font); my $w = $canvas->width(); my $h = $canvas->height(); my $GraphFrameArray = $this->{'GraphFrameArray'} = new GraphFrameArray($this->mw()); $GraphFrameArray->SetCanvasSize($w, $h); $GraphFrameArray->AddGraphFrame(); my $GraphFrame0 = $GraphFrameArray->GetGraphFrame(0); my $FramePosStr0 = $App->{"GraphFrame0Position"}; $GraphFrame0->SetPositionByStr($FramePosStr0); my $XScale0 = $GraphFrame0->GetXScale(0); my $YScale0 = $GraphFrame0->GetYScale(0); $XScale0->SetScaleStringVisible(1); $XScale0->SetCaptionVisible(1); $GraphFrame0->SetViewRange(0, 0, 1, 1); } sub AssignGraphData { my ($this, $ResetViewRange) = @_; $ResetViewRange = 1 if(!defined $ResetViewRange); my $GraphFrameArray = $this->GetGraphFrameArray(); my @GraphFrame; $GraphFrame[0] = $GraphFrameArray->GetGraphFrame(0); $GraphFrame[0]->ClearAllData(); my $YLabel = ''; my $XLabel = $this->{ChooseTransmittanceXListBox}->GetText(); my $Y1Label = $this->{ChooseTransmittanceY1ListBox}->GetText(); my $Y2Label = $this->{ChooseReflectanceY1ListBox}->GetText(); $GraphFrame[0]->SetXCaption($XLabel); $YLabel = $Y1Label if($Y1Label); $YLabel = "$YLabel $Y2Label" if($Y2Label); $GraphFrame[0]->SetYCaption($YLabel); my $pX1 = $this->{TransmittanceDataFile}->GetXData($XLabel) if($XLabel); my $pY1 = $this->{TransmittanceDataFile}->GetYData($Y1Label) if($Y1Label); my $pX2 = $this->{ReflectanceDataFile}->GetXData($XLabel) if($XLabel); my $pY2 = $this->{ReflectanceDataFile}->GetYData($Y2Label) if($Y2Label); my $nData = $this->{TransmittanceDataFile}->nData(); if($pX1 or $pX2) { $GraphFrame[0]->AddGraphData($pX1, $pY1, 2, "black", "", 6, "red", 0, "red", "XAutoSkip", "Energy", "T") if($pY1); $GraphFrame[0]->AddGraphData($pX2, $pY2, 2, "red", "", 6, "red", 0, "red", "XAutoSkip", "Energy", "R") if($pY2); } my $pCalX = $this->{CalX}; my $pCalY1 = $this->{CalY1}; my $pCalY2 = $this->{CalY2}; if($pCalX) { $GraphFrame[0]->AddGraphData($pCalX, $pCalY1, 0, "black", "circle", 3, "", 1, "black", "XAutoSkip", "Energy", "T") if($pCalY1); $GraphFrame[0]->AddGraphData($pCalX, $pCalY2, 0, "red", "circle", 3, "", 1, "red", "XAutoSkip", "Energy", "R") if($pCalY2); } $GraphFrame[0]->SetYScalePlotType('x'); if($ResetViewRange) { $GraphFrame[0]->CalMinMax(); $GraphFrame[0]->AdjustViewRange(0.05, 0.05, 0.05, 0.05); } } 1;