1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkPeriodicTable.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10   This software is distributed WITHOUT ANY WARRANTY; without even
11   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12   PURPOSE.  See the above copyright notice for more information.
13 
14   =========================================================================*/
15 
16 // Hide VTK_DEPRECATED_IN_9_1_0() warnings for this class.
17 #define VTK_DEPRECATION_LEVEL 0
18 
19 #include "vtkPeriodicTable.h"
20 
21 #include "vtkAbstractArray.h"
22 #include "vtkBlueObeliskData.h"
23 #include "vtkColor.h"
24 #include "vtkDebugLeaks.h"
25 #include "vtkFloatArray.h"
26 #include "vtkLookupTable.h"
27 #include "vtkObjectFactory.h"
28 #include "vtkStdString.h"
29 #include "vtkStringArray.h"
30 #include "vtkUnsignedShortArray.h"
31 
32 #include <cassert>
33 #include <cctype>
34 #include <cstring>
35 #include <string>
36 
37 // Setup static variables
38 vtkNew<vtkBlueObeliskData> vtkPeriodicTable::BlueObeliskData;
39 
40 //------------------------------------------------------------------------------
41 vtkStandardNewMacro(vtkPeriodicTable);
42 
43 //------------------------------------------------------------------------------
vtkPeriodicTable()44 vtkPeriodicTable::vtkPeriodicTable()
45 {
46   vtkPeriodicTable::BlueObeliskData->LockWriteMutex();
47 
48   if (!vtkPeriodicTable::BlueObeliskData->IsInitialized())
49   {
50     vtkPeriodicTable::BlueObeliskData->Initialize();
51   }
52 
53   vtkPeriodicTable::BlueObeliskData->UnlockWriteMutex();
54 }
55 
56 //------------------------------------------------------------------------------
57 vtkPeriodicTable::~vtkPeriodicTable() = default;
58 
59 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)60 void vtkPeriodicTable::PrintSelf(ostream& os, vtkIndent indent)
61 {
62   this->Superclass::PrintSelf(os, indent);
63 
64   os << indent << "BlueObeliskData:\n";
65   vtkPeriodicTable::BlueObeliskData->PrintSelf(os, indent.GetNextIndent());
66 }
67 
68 //------------------------------------------------------------------------------
GetNumberOfElements()69 unsigned short vtkPeriodicTable::GetNumberOfElements()
70 {
71   return vtkPeriodicTable::BlueObeliskData->GetNumberOfElements();
72 }
73 
74 //------------------------------------------------------------------------------
GetSymbol(unsigned short atomicNum)75 const char* vtkPeriodicTable::GetSymbol(unsigned short atomicNum)
76 {
77   if (atomicNum > this->GetNumberOfElements())
78   {
79     vtkWarningMacro("Atomic number out of range ! Using 0 instead of " << atomicNum);
80     atomicNum = 0;
81   }
82 
83   return vtkPeriodicTable::BlueObeliskData->GetSymbols()->GetValue(atomicNum).c_str();
84 }
85 
86 //------------------------------------------------------------------------------
GetElementName(unsigned short atomicNum)87 const char* vtkPeriodicTable::GetElementName(unsigned short atomicNum)
88 {
89   if (atomicNum > this->GetNumberOfElements())
90   {
91     vtkWarningMacro("Atomic number out of range ! Using 0 instead of " << atomicNum);
92     atomicNum = 0;
93   }
94 
95   return vtkPeriodicTable::BlueObeliskData->GetNames()->GetValue(atomicNum).c_str();
96 }
97 
98 //------------------------------------------------------------------------------
GetAtomicNumber(const vtkStdString & str)99 unsigned short vtkPeriodicTable::GetAtomicNumber(const vtkStdString& str)
100 {
101   return this->GetAtomicNumber(str.c_str());
102 }
103 
104 //------------------------------------------------------------------------------
GetAtomicNumber(const char * str)105 unsigned short vtkPeriodicTable::GetAtomicNumber(const char* str)
106 {
107   // If the string is null or the BODR object is not initialized, just
108   // return 0.
109   if (!str)
110   {
111     return 0;
112   }
113 
114   // First attempt to just convert the string to an integer. If this
115   // works, return the integer
116   int atoi_num = atoi(str);
117   if (atoi_num > 0 && atoi_num <= static_cast<int>(this->GetNumberOfElements()))
118   {
119     return static_cast<unsigned short>(atoi_num);
120   }
121 
122   // Convert str to lowercase (see note about casts in
123   // https://en.cppreference.com/w/cpp/string/byte/tolower)
124   std::string lowerStr(str);
125   std::transform(lowerStr.cbegin(), lowerStr.cend(), lowerStr.begin(),
126     [](unsigned char c) -> char { return static_cast<char>(std::tolower(c)); });
127 
128   // Cache pointers:
129   vtkStringArray* lnames = vtkPeriodicTable::BlueObeliskData->GetLowerNames();
130   vtkStringArray* lsymbols = vtkPeriodicTable::BlueObeliskData->GetLowerSymbols();
131   const unsigned short numElements = this->GetNumberOfElements();
132 
133   // Compare with other lowercase strings
134   for (unsigned short ind = 0; ind <= numElements; ++ind)
135   {
136     if (lnames->GetValue(ind) == lowerStr || lsymbols->GetValue(ind) == lowerStr)
137     {
138       return ind;
139     }
140   }
141 
142   // Manually test some non-standard names:
143   // - Deuterium
144   if (lowerStr == "d" || lowerStr == "deuterium")
145   {
146     return 1;
147   }
148   // - Tritium
149   else if (lowerStr == "t" || lowerStr == "tritium")
150   {
151     return 1;
152   }
153   // - Aluminum (vs. Aluminium)
154   else if (lowerStr == "aluminum")
155   {
156     return 13;
157   }
158 
159   return 0;
160 }
161 
162 //------------------------------------------------------------------------------
GetCovalentRadius(unsigned short atomicNum)163 float vtkPeriodicTable::GetCovalentRadius(unsigned short atomicNum)
164 {
165   if (atomicNum > this->GetNumberOfElements())
166   {
167     vtkWarningMacro("Atomic number out of range ! Using 0 instead of " << atomicNum);
168     atomicNum = 0;
169   }
170 
171   return vtkPeriodicTable::BlueObeliskData->GetCovalentRadii()->GetValue(atomicNum);
172 }
173 
174 //------------------------------------------------------------------------------
GetVDWRadius(unsigned short atomicNum)175 float vtkPeriodicTable::GetVDWRadius(unsigned short atomicNum)
176 {
177   if (atomicNum > this->GetNumberOfElements())
178   {
179     vtkWarningMacro("Atomic number out of range ! Using 0 instead of " << atomicNum);
180     atomicNum = 0;
181   }
182 
183   return vtkPeriodicTable::BlueObeliskData->GetVDWRadii()->GetValue(atomicNum);
184 }
185 
186 //------------------------------------------------------------------------------
GetMaxVDWRadius()187 float vtkPeriodicTable::GetMaxVDWRadius()
188 {
189   float maxRadius = 0;
190   for (unsigned short i = 0; i < this->GetNumberOfElements(); i++)
191   {
192     maxRadius = std::max(maxRadius, this->GetVDWRadius(i));
193   }
194   return maxRadius;
195 }
196 
197 //------------------------------------------------------------------------------
GetDefaultLUT(vtkLookupTable * lut)198 void vtkPeriodicTable::GetDefaultLUT(vtkLookupTable* lut)
199 {
200   const unsigned short numColors = this->GetNumberOfElements() + 1;
201   vtkFloatArray* colors = vtkPeriodicTable::BlueObeliskData->GetDefaultColors();
202   lut->SetNumberOfColors(numColors);
203   lut->SetIndexedLookup(true);
204   float rgb[3];
205   for (vtkIdType i = 0; static_cast<unsigned int>(i) < numColors; ++i)
206   {
207     colors->GetTypedTuple(i, rgb);
208     lut->SetTableValue(i, rgb[0], rgb[1], rgb[2]);
209     lut->SetAnnotation(i, this->GetSymbol(static_cast<unsigned short>(i)));
210   }
211 }
212 
213 //------------------------------------------------------------------------------
GetDefaultRGBTuple(unsigned short atomicNum,float rgb[3])214 void vtkPeriodicTable::GetDefaultRGBTuple(unsigned short atomicNum, float rgb[3])
215 {
216   vtkPeriodicTable::BlueObeliskData->GetDefaultColors()->GetTypedTuple(atomicNum, rgb);
217 }
218 
219 //------------------------------------------------------------------------------
GetDefaultRGBTuple(unsigned short atomicNum)220 vtkColor3f vtkPeriodicTable::GetDefaultRGBTuple(unsigned short atomicNum)
221 {
222   vtkColor3f result;
223   vtkPeriodicTable::BlueObeliskData->GetDefaultColors()->GetTypedTuple(atomicNum, result.GetData());
224   return result;
225 }
226