package Crystal::OpenGL; use Exporter; @ISA = qw(Exporter); #公開したいサブルーチン @EXPORT = qw(); use strict; use File::Basename; use Sci::Science; use Graphics::OpenGL; use Crystal::Crystal; use Crystal::AtomType; use Crystal::AtomSite; use Crystal::CIF; BEGIN { } sub new { my ($module) = @_; my $this = {}; bless $this; return $this; } sub DESTROY { my $this = shift; } sub SetSampleName { my ($this, $name) = @_; return $this->{'SampleName'} = $name; } sub SampleName { my ($this) = @_; return $this->{'SampleName'}; } sub DrawLattice { my ($this, $OGL, $Crystal, $material) = @_; my $r = $material->{-Radius}; my ($a11,$a12,$a13,$a21,$a22,$a23,$a31,$a32,$a33) = $Crystal->LatticeVectors(); $OGL->DrawCylinder(0, 0, 0, $a11, $a12, $a13, $r, $material, 12); $OGL->DrawCylinder(0, 0, 0, $a21, $a22, $a23, $r, $material, 12); $OGL->DrawCylinder(0, 0, 0, $a31, $a32, $a33, $r, $material, 12); $OGL->DrawCylinder(0+$a11, 0+$a12, 0+$a13, $a21+$a11, $a22+$a12, $a23+$a13, $r, $material, 12); $OGL->DrawCylinder(0+$a11, 0+$a12, 0+$a13, $a31+$a11, $a32+$a12, $a33+$a13, $r, $material, 12); $OGL->DrawCylinder( 0+$a21, 0+$a22, 0+$a23, $a11+$a21, $a12+$a22, $a13+$a23, $r, $material, 12); $OGL->DrawCylinder(0+$a21+$a31, 0+$a22+$a32, 0+$a23+$a33, $a11+$a21+$a31, $a12+$a22+$a32, $a13+$a23+$a33, $r, $material, 12); $OGL->DrawCylinder(0+$a21, 0+$a22, 0+$a23, $a31+$a21, $a32+$a22, $a33+$a23, $r, $material, 12); $OGL->DrawCylinder(0+$a31, 0+$a32, 0+$a33, $a11+$a31, $a12+$a32, $a13+$a33, $r, $material, 12); $OGL->DrawCylinder(0+$a31, 0+$a32, 0+$a33, $a21+$a31, $a22+$a32, $a23+$a33, $r, $material, 12); $OGL->DrawCylinder(0+$a11+$a31, 0+$a12+$a32, 0+$a13+$a33, $a21+$a11+$a31, $a22+$a12+$a32, $a23+$a13+$a33, $r, $material, 12); $OGL->DrawCylinder(0+$a11+$a21, 0+$a12+$a22, 0+$a13+$a23, $a31+$a11+$a21, $a32+$a12+$a22, $a33+$a13+$a23, $r, $material, 12); } sub Prepare { my ($this, $OGL, $Crystal, $nx, $ny, $nz, $rScale) = @_; $this->{DidPrepare} = 1; my @AtomTypeList = $Crystal->GetCAtomTypeList(); my $nAtomType = @AtomTypeList; my @ExpandedAtomSiteList = $Crystal->GetCExpandedAtomSiteList(); my $nExpandedAtomSite = @ExpandedAtomSiteList; my %Material; $Material{CellBar} = new Graphics::OpenGLMaterial( -Diffuse => [0.5, 0.5, 0.5, 1.0], -Ambient => [0.5, 0.5, 0.5, 1.0], -Specular => [0.5, 0.5, 0.5, 1.0], -Emission => [0.5, 0.5, 0.5, 1.0], -Shininess => [50.0], -Radius => 0.05, ); # $this->DrawLattice($OGL, $Crystal, $Material{CellBar}); my $ColorOffset = 0.3; for(my $i = 0 ; $i < @AtomTypeList ; $i++) { my $AtomType = $AtomTypeList[$i]; my $atomname = $AtomType->AtomNameOnly(); my $radius = $AtomType->IonRadius(); #AtomicRadius(); $radius = 0.6 if($radius <= 0); $radius *= $rScale; if(!$Material{$atomname}) { my $red = $ColorOffset + rand(1.0-$ColorOffset); my $green = $ColorOffset + rand(1.0-$ColorOffset); my $blue = $ColorOffset + rand(1.0-$ColorOffset); $red /= 3 if($i % 3 == 0); $green /= 3 if($i % 3 == 1); $blue /= 3 if($i % 3 == 2); $Material{$atomname} = new Graphics::OpenGLMaterial( -Diffuse => [$red, $green, $blue, 1.0], -Ambient => [$red, $green, $blue, 1.0], -Specular => [$red, $green, $blue, 1.0], # -Emission => [$red, $green, $blue, 1.0], -Shininess => [50.0], -Radius => $radius, ); } } my @ViewSites; my $nViewSites = 0; my $inx = int($nx-0.01) + 1; my $iny = int($ny-0.01) + 1; my $inz = int($nz-0.01) + 1; my %nAtomTypes; for(my $ix = -1 ; $ix <= $inx ; $ix++) { for(my $iy = -1 ; $iy <= $iny ; $iy++) { for(my $iz = -1 ; $iz <= $inz ; $iz++) { for(my $i = 0 ; $i < $nExpandedAtomSite ; $i++) { my $AtomSite = $ExpandedAtomSiteList[$i]; my $SiteLabel = $AtomSite->Label(); my $atomname = $AtomSite->AtomNameOnly(); my $charge = $AtomSite->Charge(); my $occ = $AtomSite->Occupancy(); my ($x,$y,$z) = $AtomSite->Position(1); #print "$atomname: ($x,$y,$z)+($ix,$iy,$iz)$LF"; my $material = $Material{$atomname}; $x += $ix; $y += $iy; $z += $iz; next if($x < 0 or $nx < $x); next if($y < 0 or $ny < $y); next if($z < 0 or $nz < $z); #print "$atomname: ($x,$y,$z)$LF"; my $occupancy = $AtomSite->Occupancy(); #print "x [$i][$nViewSites] =$x, $y, $z\n"; my ($xc, $yc, $zc) = $Crystal->FractionalToCartesian($x, $y, $z); # my $occscale = (0.3 + $occupancy) / 1.3; # $OGL->DrawSphere($xc, $yc, $zc, $material->{-Radius}, $material, 12); $ViewSites[$nViewSites] = new AtomSite; $ViewSites[$nViewSites]->SetLabel($SiteLabel); $ViewSites[$nViewSites]->SetAtomName($atomname); $ViewSites[$nViewSites]->SetOccupancy($occ); $ViewSites[$nViewSites]->SetPosition($x, $y, $z); $nViewSites++; } } } } $this->{pMaterial} = \%Material; $this->{pViewSites} = \@ViewSites; } sub Draw { my ($this, $OGL, $Crystal, $nx, $ny, $nz, $MaxBondLength, $nMaxBonds, $rScale) = @_; $this->Prepare($OGL, $Crystal, $nx, $ny, $nz, $rScale) if(!$this->{DidPrepare}); my $pMaterial = $this->{pMaterial}; my $pViewSites = $this->{pViewSites}; my $nViewSites = @$pViewSites; my ($a11,$a12,$a13,$a21,$a22,$a23,$a31,$a32,$a33) = $Crystal->LatticeVectors(); $OGL->SetOffset(($a11+$a21+$a31)/3.0, ($a12+$a22+$a32)/3.0, ($a13+$a23+$a33)/3.0); $this->DrawLattice($OGL, $Crystal, $pMaterial->{CellBar}); for(my $i = 0 ; $i < $nViewSites ; $i++) { my $AtomSite = $pViewSites->[$i]; my ($x,$y,$z) = $AtomSite->Position(); my $atomname = $AtomSite->AtomNameOnly(); my $material = $pMaterial->{$atomname}; my ($xc, $yc, $zc) = $Crystal->FractionalToCartesian($x, $y, $z); $OGL->DrawSphere($xc, $yc, $zc, $material->{-Radius}, $material, 12); } my $BondMaterial = new Graphics::OpenGLMaterial( -Diffuse => [0.9, 0.9, 0.9, 1.0], -Ambient => [0.9, 0.9, 0.9, 1.0], -Specular => [0.9, 0.9, 0.9, 1.0], -Emission => [0.9, 0.9, 0.9, 1.0], -Shininess => [50.0], -Radius => 0.05, ); my $MaxBondLength2 = $MaxBondLength * $MaxBondLength; my $count = 0; for(my $i = 0 ; $i < $nViewSites ; $i++) { my $atom0 = $pViewSites->[$i]; my ($x0,$y0,$z0) = $atom0->Position(0); my ($xc0, $yc0, $zc0) = $Crystal->FractionalToCartesian($x0, $y0, $z0); for(my $j = $i+1 ; $j < $nViewSites ; $j++) { my $atom1 = $pViewSites->[$j]; my ($x1,$y1,$z1) = $atom1->Position(0); my ($xc1, $yc1, $zc1) = $Crystal->FractionalToCartesian($x1, $y1, $z1); my $dx = $xc1 - $xc0; my $dy = $yc1 - $yc0; my $dz = $zc1 - $zc0; my $dis2 = $dx*$dx + $dy*$dy + $dz*$dz; #print "($i,$j) ($x0,$y0,$z0)-($x1,$y1,$z1) $dis2 ($MaxBondLength2)\n"; next if($dis2 < 0.01 or $dis2 > $MaxBondLength2); $OGL->DrawCylinder($xc0, $yc0, $zc0, $xc1, $yc1, $zc1, $BondMaterial->{-Radius}, $BondMaterial, 12); $count++; if($count > $nMaxBonds) { print "Number of bonds reaches maximum ($nMaxBonds).\n"; last; } } last if($count > $nMaxBonds); } # my ($a11,$a12,$a13,$a21,$a22,$a23,$a31,$a32,$a33) = $Crystal->LatticeVectors(); # $OGL->Translated(-($a11+$a21+$a31)/3.0, -($a12+$a22+$a32)/3.0, -($a13+$a23+$a33)/3.0); } 1;