1 // ATOM.CPP
2 
3 // Copyright (C) 1998 Tommi Hassinen.
4 
5 // This package is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 
10 // This package is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 
15 // You should have received a copy of the GNU General Public License
16 // along with this package; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 
19 /*################################################################################################*/
20 
21 #include "libghemicalconfig2.h"
22 #include "atom.h"
23 
24 #include "bond.h"
25 #include "local_i18n.h"
26 #include "notice.h"
27 
28 #include <cstring>
29 using namespace std;
30 
31 /*################################################################################################*/
32 
33 element element::current_element = element("C");
34 
35 const char element::string[ELEMENT_SYMBOLS][32] =
36 {
37 	"hydrogen", "helium", "lithium", "beryllium", "boron",
38 	"carbon", "nitrogen", "oxygen", "fluorine", "neon",				// 10
39 	"sodium", "magnesium", "aluminium", "silicon", "phosphorus",
40 	"sulphur", "chlorine", "argon", "potassium", "calcium",				// 20
41 	"scandium", "titanium", "vanadium", "chromium", "manganese",
42 	"iron", "cobalt", "nickel", "copper", "zinc",					// 30
43 	"gallium", "germanium", "arsenic", "selenium", "bromine",
44 	"krypton", "rubidium", "strontium", "yttrium", "zirconium",			// 40
45 	"niobium", "molybdenum", "technetium", "ruthenium", "rhodium",
46 	"palladium", "silver", "cadmium", "indium", "tin",				// 50
47 	"antimony", "tellurium", "iodine", "xenon", "cesium",
48 	"barium", "lanthanum", "cerium", "praseodymium", "neodymium",			// 60
49 	"promethium", "samarium", "europium", "gadolinium", "terbium",
50 	"dysprosium", "holmium", "erbium", "thulium", "ytterbium",			// 70
51 	"lutetium", "hafnium", "tantalum", "tungsten", "rhenium",
52 	"osmium", "iridium", "platinum", "gold", "mercury",				// 80
53 	"thallium", "lead", "bismuth", "polonium", "astatine",
54 	"radon", "francium", " radium", "actinium", "thorium",				// 90
55 	"protactinium", "uranium", "neptunium", "plutionium", "americium",
56 	"curium", "berkelium", "californium", "einsteinium", "fermium",			// 100
57 	"mendelevium", "nobelium", "lawrencium", "rutherfordium", "dubnium",
58 	"seaborgium", "bohrium", "hassium", "meitnerium", "ununnilium"			// 110
59 };
60 
61 const char element::symbol[ELEMENT_SYMBOLS][4] =
62 {
63 	"H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne",
64 	"Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca",		// 20
65 	"Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn",
66 	"Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr",		// 40
67 	"Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn",
68 	"Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd",		// 60
69 	"Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb",
70 	"Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg",		// 80
71 	"Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th",
72 	"Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm",		// 100
73 	"Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Uun"
74 };
75 
76 // These are the defaults--modified via the prefs class.
77 // REMOVE CONST AND MODIFY THESE DIRECTLY?!?!?!?!
78 
79 const fGL element::color[ELEMENT_SYMBOLS][3] =
80 {
81     { 1.00, 1.00, 1.00 }, { 0.85, 1.00, 1.00 }, { 0.80, 0.50, 1.00 },
82     { 0.76, 1.00, 0.00 }, { 1.00, 0.71, 0.71 }, { 0.56, 0.56, 0.56 },	// 6
83     { 0.18, 0.31, 0.97 }, { 1.00, 0.05, 0.05 }, { 0.56, 0.87, 0.31 },
84     { 0.70, 0.89, 0.96 }, { 0.67, 0.36, 0.95 }, { 0.54, 1.00, 0.00 },	// 12
85     { 0.75, 0.65, 0.65 }, { 0.94, 0.78, 0.62 }, { 1.00, 0.50, 0.00 },
86     { 1.00, 1.00, 0.19 }, { 0.12, 0.94, 0.12 }, { 0.50, 0.82, 0.89 },	// 18
87     { 0.56, 0.25, 0.83 }, { 0.24, 1.00, 0.00 }, { 0.90, 0.90, 0.90 },
88     { 0.75, 0.76, 0.78 }, { 0.65, 0.65, 0.67 }, { 0.54, 0.60, 0.78 },	// 24
89     { 0.61, 0.48, 0.78 }, { 0.87, 0.40, 0.20 }, { 0.94, 0.56, 0.62 },
90     { 0.31, 0.81, 0.31 }, { 0.78, 0.50, 0.20 }, { 0.49, 0.50, 0.69 },	// 30
91     { 0.76, 0.56, 0.56 }, { 0.40, 0.56, 0.56 }, { 0.74, 0.50, 0.89 },
92     { 1.00, 0.63, 0.00 }, { 0.65, 0.16, 0.16 }, { 0.36, 0.72, 0.82 },	// 36
93     { 0.44, 0.18, 0.69 }, { 0.00, 1.00, 0.00 }, { 0.58, 1.00, 1.00 },
94     { 0.58, 0.88, 0.88 }, { 0.45, 0.76, 0.79 }, { 0.33, 0.71, 0.71 },	// 42
95     { 0.23, 0.62, 0.62 }, { 0.14, 0.56, 0.56 }, { 0.04, 0.49, 0.55 },
96     { 0.00, 0.41, 0.52 }, { 0.75, 0.75, 0.75 }, { 1.00, 0.85, 0.56 },	// 48
97     { 0.65, 0.46, 0.45 }, { 0.40, 0.50, 0.50 }, { 0.62, 0.39, 0.71 },
98     { 0.83, 0.48, 0.00 }, { 0.58, 0.00, 0.58 }, { 0.26, 0.62, 0.69 },	// 54
99     { 0.34, 0.09, 0.56 }, { 0.00, 0.79, 0.00 }, { 0.44, 0.83, 1.00 },
100     { 1.00, 1.00, 0.78 }, { 0.85, 1.00, 0.78 }, { 0.78, 1.00, 0.78 },	// 60
101     { 0.64, 1.00, 0.78 }, { 0.56, 1.00, 0.78 }, { 0.38, 1.00, 0.78 },
102     { 0.27, 1.00, 0.78 }, { 0.19, 1.00, 0.78 }, { 0.12, 1.00, 0.78 },	// 66
103     { 0.00, 1.00, 0.61 }, { 0.00, 0.90, 0.46 }, { 0.00, 0.83, 0.32 },
104     { 0.00, 0.75, 0.22 }, { 0.00, 0.67, 0.14 }, { 0.30, 0.76, 1.00 },	// 72
105     { 0.30, 0.65, 1.00 }, { 0.13, 0.58, 0.84 }, { 0.15, 0.49, 0.67 },
106     { 0.15, 0.40, 0.59 }, { 0.09, 0.33, 0.53 }, { 0.81, 0.81, 0.87 },	// 78
107     { 1.00, 0.81, 0.13 }, { 0.72, 0.72, 0.81 }, { 0.65, 0.33, 0.30 },
108     { 0.34, 0.35, 0.38 }, { 0.62, 0.31, 0.71 }, { 0.67, 0.36, 0.00 },	// 84
109     { 0.46, 0.31, 0.27 }, { 0.26, 0.51, 0.59 }, { 0.26, 0.00, 0.40 },
110     { 0.00, 0.49, 0.00 }, { 0.44, 0.67, 0.98 }, { 0.00, 0.73, 1.00 },	// 90
111     { 0.00, 0.63, 1.00 }, { 0.00, 0.56, 1.00 }, { 0.00, 0.50, 1.00 },
112     { 0.00, 0.42, 1.00 }, { 0.33, 0.36, 0.95 }, { 0.47, 0.36, 0.89 },	// 96
113     { 0.54, 0.31, 0.89 }, { 0.63, 0.21, 0.83 }, { 0.70, 0.12, 0.83 },
114     { 0.70, 0.12, 0.73 }, { 0.70, 0.05, 0.65 }, { 0.74, 0.05, 0.53 },	// 102
115     { 0.78, 0.00, 0.40 }, { 0.80, 0.00, 0.35 }, { 0.82, 0.00, 0.31 },
116     { 0.85, 0.00, 0.27 }, { 0.88, 0.00, 0.22 }, { 0.90, 0.00, 0.18 },	// 108
117     { 0.92, 0.00, 0.15 }, { 0.95, 0.00, 0.11 }
118 };
119 
120 // IUPAC recognized masses rounded to 0.001 where appropriate
121 // From _Pure Appl. Chem., 71 (1999) 1593-1607.
122 // these are in normal atomic mass units... TH
123 
124 const fGL element::mass[ELEMENT_SYMBOLS] =
125 {
126 	1.008, 4.003, 6.941, 9.012, 10.812,
127 	12.011, 14.007, 15.999, 18.998, 20.180,			// 10
128 	22.990, 24.305, 26.982, 28.086, 30.974,
129 	32.067, 35.453, 39.948, 39.098, 40.078,			// 20
130 	44.956, 47.867, 50.942, 51.996, 54.938,
131 	55.845, 58.933, 58.693, 63.546, 65.39,			// 30
132 	69.723, 72.61, 74.922, 78.96, 79.904,
133 	83.80, 85.468, 87.62, 88.906, 91.224,			// 40
134 	92.906, 95.94, 98.0, 101.07, 102.906,
135 	106.42, 107.868, 112.412, 114.818, 118.711,		// 50
136 	121.760, 127.60, 126.904, 131.29, 132.905,
137 	137.328, 138.906, 140.116, 140.908, 144.24,		// 60
138 	145.0, 150.36, 151.964, 157.25, 158.925,
139 	162.50, 164.930, 167.26, 168.934, 173.04,		// 70
140 	174.967, 178.49, 180.948, 183.84, 186.207,
141 	190.23, 192.217, 195.078, 196.967, 200.59,		// 80
142 	204.383, 207.2, 208.980, 209.0, 210.0,
143 	222.0, 223.0, 226.0, 227.0, 232.038,			// 90
144 	231.036, 238.029, 237.0, 244.0, 243.0,
145 	247.0, 247.0, 251.0, 252.0, 257.0,			// 100
146 	258.0, 259.0, 262.0, 261.0, 262.0,
147 	263.0, 264.0, 265.0, 268.0, 269.0			// 110
148 };
149 
150 // van der Waals radii for graphics--these determine the size of the spheres
151 // These were collected from the elements list in Open Babel
152 // (0.170 nm seems to be an "unknown" value
153 
154 const fGL element::vdwr[ELEMENT_SYMBOLS] =
155 {
156 	0.120, 0.140, 0.180, 0.170, 0.208, 0.170, 0.155, 0.150, 0.155, 0.160,
157 	0.231, 0.170, 0.205, 0.210, 0.185, 0.180, 0.181, 0.191, 0.280, 0.197,		// 20
158 	0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.160, 0.140, 0.140,
159 	0.190, 0.170, 0.185, 0.190, 0.190, 0.200, 0.244, 0.170, 0.170, 0.170,		// 40
160 	0.170, 0.170, 0.170, 0.170, 0.170, 0.163, 0.172, 0.160, 0.190, 0.220,
161 	0.220, 0.210, 0.198, 0.220, 0.262, 0.170, 0.170, 0.170, 0.170, 0.170,		// 60
162 	0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170,
163 	0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.175, 0.166, 0.155,		// 80
164 	0.200, 0.202, 0.240, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170,
165 	0.170, 0.190, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170,		// 100
166 	0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170
167 };
168 
element(void)169 element::element(void)
170 {
171 	atomic_number = NOT_DEFINED;	// set to a dummy atom by default!!!
172 }
173 
174 // unknown symbols are thought to be "wildcard elements" which MUST have their atomic numbers
175 // equal to minus one (that is, NOT_DEFINED). if this logic is changed, some bad problems will
176 // emerge in the ring search and in typerules...
177 
element(char * p1)178 element::element(char * p1)
179 {
180 	i32s n1 = 0;
181 	while (n1 < ELEMENT_SYMBOLS && strcmp(symbol[n1], p1)) n1++;
182 
183 	if (n1 < ELEMENT_SYMBOLS) atomic_number = n1 + 1;
184 	else atomic_number = NOT_DEFINED;
185 }
186 
element(i32s p1)187 element::element(i32s p1)
188 {
189 	if (p1 < 1 || p1 > ELEMENT_SYMBOLS) atomic_number = NOT_DEFINED;
190 	else atomic_number = p1;
191 }
192 
~element(void)193 element::~element(void)
194 {
195 }
196 
GetString(void) const197 const char * element::GetString(void) const
198 {
199 	if (atomic_number == NOT_DEFINED) return "DUMMY_ATOM";
200 	else return string[atomic_number - 1];
201 }
202 
GetAtomicNumber(void) const203 const i32s element::GetAtomicNumber(void) const
204 {
205 	return atomic_number;
206 }
207 
208 // the symbol for atomic_number NOT_DEFINED (= -1) might affect the atomtype rule class "typerule",
209 // but it seems to be OK to return symbol "Du" (a "wildcard" setting is selected for all unknown ones).
210 
GetSymbol(void) const211 const char * element::GetSymbol(void) const
212 {
213 	if (atomic_number == NOT_DEFINED) return "Du";
214 	else return symbol[atomic_number - 1];
215 }
216 
GetColor(void) const217 const fGL * element::GetColor(void) const
218 {
219 	static fGL not_defined_color[3] = { 0.5, 0.4, 0.3 };
220 
221 	if (atomic_number == NOT_DEFINED) return not_defined_color;	// just return something usable also in this case...
222 	else return color[atomic_number - 1];
223 }
224 
GetAtomicMass(void) const225 fGL element::GetAtomicMass(void) const
226 {
227 	if (atomic_number == NOT_DEFINED) return -1.0;
228 	else return mass[atomic_number - 1];
229 }
230 
GetVDWRadius(void) const231 fGL element::GetVDWRadius(void) const
232 {
233 	if (atomic_number == NOT_DEFINED) return -1.0;
234 	else return vdwr[atomic_number - 1];
235 }
236 
operator ++(void)237 void element::operator++(void)
238 {
239 	if (++atomic_number > ELEMENT_SYMBOLS) atomic_number = 1;
240 }
241 
operator --(void)242 void element::operator--(void)
243 {
244 	if (--atomic_number < 1) atomic_number = ELEMENT_SYMBOLS;
245 }
246 
247 /*################################################################################################*/
248 
crec(void)249 crec::crec(void)
250 {
251 	atmr = NULL;
252 	bndr = NULL;
253 }
254 
crec(atom * p1,bond * p2)255 crec::crec(atom * p1, bond * p2)
256 {
257 	atmr = p1;
258 	bndr = p2;
259 }
260 
~crec(void)261 crec::~crec(void)
262 {
263 }
264 
operator ==(const crec & p1) const265 bool crec::operator==(const crec & p1) const
266 {
267 	return (bndr == p1.bndr);
268 }
269 
270 /*################################################################################################*/
271 
atom(void)272 atom::atom(void)
273 {
274 	mdl = NULL;
275 	my_glname = GLNAME_UNREGISTERED;
276 }
277 
atom(element p1,const fGL * p2,i32u p3)278 atom::atom(element p1, const fGL * p2, i32u p3)
279 {
280 	mdl = NULL;
281 	my_glname = GLNAME_UNREGISTERED;
282 
283 	el = p1;
284 	formal_charge = 0;
285 
286 	atmtp = NOT_DEFINED;
287 	atmtp_E = NOT_DEFINED;
288 	atmtp_s[0] = 0;			// initialize to a zero-length string.
289 
290 	charge = 0.0;
291 	mass = el.GetAtomicMass();
292 
293 	vdwr = el.GetVDWRadius();
294 
295 	fGL data[3] = { 0.0, 0.0, 0.0 };	// default coordinates...
296 	if (p2 != NULL) { data[0] = p2[0]; data[1] = p2[1]; data[2] = p2[2]; }
297 
298 	crd_table_size_loc = p3;
299 	if (crd_table_size_loc < 1) assertion_failed(__FILE__, __LINE__, "crd_table_size_loc < 1");
300 
301 	crd_table = new fGL[crd_table_size_loc * 3];
302 	for (i32u n1 = 0;n1 < crd_table_size_loc;n1++)		// be sure to initialize the whole array -> valid floats!!!
303 	{
304 		crd_table[n1 * 3 + 0] = data[0];
305 		crd_table[n1 * 3 + 1] = data[1];
306 		crd_table[n1 * 3 + 2] = data[2];
307 	}
308 
309 	for (i32u i1 = 0;i1 < 4;i1++) id[i1] = NOT_DEFINED;
310 	builder_res_id = NOT_DEFINED;
311 
312 	index = NOT_DEFINED;
313 	varind = NOT_DEFINED;
314 
315 	flags = 0;
316 
317 	ecomp_grp_i = 0;	// the "default" group index is zero!
318 }
319 
atom(const atom & p1)320 atom::atom(const atom & p1)
321 {
322 	mdl = NULL;				// strict...
323 	my_glname = GLNAME_UNREGISTERED;	// strict...
324 
325 	el = p1.el;
326 	formal_charge = p1.formal_charge;
327 
328 	atmtp = p1.atmtp;
329 	atmtp_E = p1.atmtp_E;
330 	strcpy(atmtp_s, p1.atmtp_s);
331 
332 	charge = p1.charge;
333 	mass = p1.mass;
334 
335 	vdwr = p1.vdwr;
336 
337 	cr_list = p1.cr_list;
338 
339 	crd_table_size_loc = p1.crd_table_size_loc;
340 	if (crd_table_size_loc < 1) assertion_failed(__FILE__, __LINE__, "crd_table_size_loc < 1");
341 
342 	crd_table = new fGL[crd_table_size_loc * 3];
343 	for (i32u n1 = 0;n1 < crd_table_size_loc;n1++)		// copy as floats -> the arrays always should contain valid data!!!
344 	{
345 		crd_table[n1 * 3 + 0] = p1.crd_table[n1 * 3 + 0];
346 		crd_table[n1 * 3 + 1] = p1.crd_table[n1 * 3 + 1];
347 		crd_table[n1 * 3 + 2] = p1.crd_table[n1 * 3 + 2];
348 	}
349 
350 	for (i32u n1 = 0;n1 < 4;n1++) id[n1] = p1.id[n1];
351 	builder_res_id = p1.builder_res_id;
352 
353 	index = p1.index;
354 	varind = p1.varind;
355 
356 	flags = p1.flags;
357 
358 	ecomp_grp_i = p1.ecomp_grp_i;
359 }
360 
~atom(void)361 atom::~atom(void)
362 {
363 	delete[] crd_table;
364 }
365 
GetCRD(i32u cs)366 const fGL * atom::GetCRD(i32u cs)
367 {
368 	if (cs >= crd_table_size_loc) assertion_failed(__FILE__, __LINE__, "cs >= crd_table_size_loc");
369 
370 	return & (crd_table[cs * 3]);
371 }
372 
SetCRD(i32s cs,fGL x,fGL y,fGL z)373 void atom::SetCRD(i32s cs, fGL x, fGL y, fGL z)
374 {
375 	if (cs < 0)
376 	{
377 		for (i32u n1 = 0;n1 < crd_table_size_loc;n1++)		// NOT_DEFINED -> set for all csets...
378 		{
379 			crd_table[n1 * 3 + 0] = x;
380 			crd_table[n1 * 3 + 1] = y;
381 			crd_table[n1 * 3 + 2] = z;
382 		}
383 	}
384 	else
385 	{
386 		if (cs >= (i32s) crd_table_size_loc) assertion_failed(__FILE__, __LINE__, "cs >= crd_table_size_loc");
387 
388 		crd_table[cs * 3 + 0] = x;
389 		crd_table[cs * 3 + 1] = y;
390 		crd_table[cs * 3 + 2] = z;
391 	}
392 }
393 
GetSelected() const394 bool atom::GetSelected() const
395 {
396 	if (flags & ATOMFLAG_USER_SELECTED) return true;
397 	return false;
398 }
399 
SetSelected(bool l)400 void atom::SetSelected(bool l)
401 {
402 	if(l) flags |= ATOMFLAG_USER_SELECTED;
403 	else flags &= ~ATOMFLAG_USER_SELECTED;
404 }
405 
GetLocked() const406 bool atom::GetLocked() const
407 {
408 	if (flags & ATOMFLAG_USER_LOCKED) return true;
409 	return false;
410 }
411 
SetLocked(bool l)412 void atom::SetLocked(bool l)
413 {
414 	if(l) flags |= ATOMFLAG_USER_LOCKED;
415 	else flags &= ~ATOMFLAG_USER_LOCKED;
416 }
417 
418 // atoms will be sorted according to their molecule, chain and residue numbers.
419 // sorting the container will then arrange molecules/chains/residues in continuous blocks.
420 
operator <(const atom & p1) const421 bool atom::operator<(const atom & p1) const
422 {
423 	for (i32s n1 = 0;n1 < 3;n1++)
424 	{
425 		if (id[n1] != p1.id[n1]) return (id[n1] < p1.id[n1]);
426 	}
427 
428 	return false;
429 }
430 
431 // for atoms, equality is tested using pointers -> you can find the
432 // iterator (using STL's find-function) if the pointer is known.
433 
operator ==(const atom & p1) const434 bool atom::operator==(const atom & p1) const
435 {
436 	return (this == (& p1));
437 }
438 
439 /*################################################################################################*/
440 
441 // eof
442