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