With respect to the review (http://codereview.appspot.com/6815052) I have
[blender-addons-contrib.git] / io_atomblend_utilities / io_atomblend_utilities.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 import io
20 import os
21 import bpy
22 import bmesh
23
24 from math import pi, cos, sin
25 from mathutils import Vector, Matrix
26
27 # This variable contains the path of the XYZ file.
28 # It is used almost everywhere, which explains why it
29 # should stay global. First, it is empty and gets 'filled' directly
30 # after having chosen the XYZ file (see 'class LoadXYZ' further below).
31
32
33 # -----------------------------------------------------------------------------
34 #                                                  Atom and element data
35
36
37 # This is a list that contains some data of all possible elements. The structure
38 # is as follows:
39 #
40 # 1, "Hydrogen", "H", [0.0,0.0,1.0], 0.32, 0.32, 0.32 , -1 , 1.54   means
41 #
42 # No., name, short name, color, radius (used), radius (covalent), radius (atomic),
43 #
44 # charge state 1, radius (ionic) 1, charge state 2, radius (ionic) 2, ... all
45 # charge states for any atom are listed, if existing.
46 # The list is fixed and cannot be changed ... (see below)
47
48 ATOM_BLEND_ELEMENTS_DEFAULT = (
49 ( 1,      "Hydrogen",        "H", (  1.0,   1.0,   1.0), 0.32, 0.32, 0.79 , -1 , 1.54 ),
50 ( 2,        "Helium",       "He", ( 0.85,   1.0,   1.0), 0.93, 0.93, 0.49 ),
51 ( 3,       "Lithium",       "Li", (  0.8,  0.50,   1.0), 1.23, 1.23, 2.05 ,  1 , 0.68 ),
52 ( 4,     "Beryllium",       "Be", ( 0.76,   1.0,   0.0), 0.90, 0.90, 1.40 ,  1 , 0.44 ,  2 , 0.35 ),
53 ( 5,         "Boron",        "B", (  1.0,  0.70,  0.70), 0.82, 0.82, 1.17 ,  1 , 0.35 ,  3 , 0.23 ),
54 ( 6,        "Carbon",        "C", ( 0.56,  0.56,  0.56), 0.77, 0.77, 0.91 , -4 , 2.60 ,  4 , 0.16 ),
55 ( 7,      "Nitrogen",        "N", ( 0.18,  0.31,  0.97), 0.75, 0.75, 0.75 , -3 , 1.71 ,  1 , 0.25 ,  3 , 0.16 ,  5 , 0.13 ),
56 ( 8,        "Oxygen",        "O", (  1.0,  0.05,  0.05), 0.73, 0.73, 0.65 , -2 , 1.32 , -1 , 1.76 ,  1 , 0.22 ,  6 , 0.09 ),
57 ( 9,      "Fluorine",        "F", ( 0.56,  0.87,  0.31), 0.72, 0.72, 0.57 , -1 , 1.33 ,  7 , 0.08 ),
58 (10,          "Neon",       "Ne", ( 0.70,  0.89,  0.96), 0.71, 0.71, 0.51 ,  1 , 1.12 ),
59 (11,        "Sodium",       "Na", ( 0.67,  0.36,  0.94), 1.54, 1.54, 2.23 ,  1 , 0.97 ),
60 (12,     "Magnesium",       "Mg", ( 0.54,   1.0,   0.0), 1.36, 1.36, 1.72 ,  1 , 0.82 ,  2 , 0.66 ),
61 (13,     "Aluminium",       "Al", ( 0.74,  0.65,  0.65), 1.18, 1.18, 1.82 ,  3 , 0.51 ),
62 (14,       "Silicon",       "Si", ( 0.94,  0.78,  0.62), 1.11, 1.11, 1.46 , -4 , 2.71 , -1 , 3.84 ,  1 , 0.65 ,  4 , 0.42 ),
63 (15,    "Phosphorus",        "P", (  1.0,  0.50,   0.0), 1.06, 1.06, 1.23 , -3 , 2.12 ,  3 , 0.44 ,  5 , 0.35 ),
64 (16,        "Sulfur",        "S", (  1.0,   1.0,  0.18), 1.02, 1.02, 1.09 , -2 , 1.84 ,  2 , 2.19 ,  4 , 0.37 ,  6 , 0.30 ),
65 (17,      "Chlorine",       "Cl", ( 0.12,  0.94,  0.12), 0.99, 0.99, 0.97 , -1 , 1.81 ,  5 , 0.34 ,  7 , 0.27 ),
66 (18,         "Argon",       "Ar", ( 0.50,  0.81,  0.89), 0.98, 0.98, 0.88 ,  1 , 1.54 ),
67 (19,     "Potassium",        "K", ( 0.56,  0.25,  0.83), 2.03, 2.03, 2.77 ,  1 , 0.81 ),
68 (20,       "Calcium",       "Ca", ( 0.23,   1.0,   0.0), 1.74, 1.74, 2.23 ,  1 , 1.18 ,  2 , 0.99 ),
69 (21,      "Scandium",       "Sc", ( 0.90,  0.90,  0.90), 1.44, 1.44, 2.09 ,  3 , 0.73 ),
70 (22,      "Titanium",       "Ti", ( 0.74,  0.76,  0.78), 1.32, 1.32, 2.00 ,  1 , 0.96 ,  2 , 0.94 ,  3 , 0.76 ,  4 , 0.68 ),
71 (23,      "Vanadium",        "V", ( 0.65,  0.65,  0.67), 1.22, 1.22, 1.92 ,  2 , 0.88 ,  3 , 0.74 ,  4 , 0.63 ,  5 , 0.59 ),
72 (24,      "Chromium",       "Cr", ( 0.54,   0.6,  0.78), 1.18, 1.18, 1.85 ,  1 , 0.81 ,  2 , 0.89 ,  3 , 0.63 ,  6 , 0.52 ),
73 (25,     "Manganese",       "Mn", ( 0.61,  0.47,  0.78), 1.17, 1.17, 1.79 ,  2 , 0.80 ,  3 , 0.66 ,  4 , 0.60 ,  7 , 0.46 ),
74 (26,          "Iron",       "Fe", ( 0.87,   0.4,   0.2), 1.17, 1.17, 1.72 ,  2 , 0.74 ,  3 , 0.64 ),
75 (27,        "Cobalt",       "Co", ( 0.94,  0.56,  0.62), 1.16, 1.16, 1.67 ,  2 , 0.72 ,  3 , 0.63 ),
76 (28,        "Nickel",       "Ni", ( 0.31,  0.81,  0.31), 1.15, 1.15, 1.62 ,  2 , 0.69 ),
77 (29,        "Copper",       "Cu", ( 0.78,  0.50,   0.2), 1.17, 1.17, 1.57 ,  1 , 0.96 ,  2 , 0.72 ),
78 (30,          "Zinc",       "Zn", ( 0.49,  0.50,  0.69), 1.25, 1.25, 1.53 ,  1 , 0.88 ,  2 , 0.74 ),
79 (31,       "Gallium",       "Ga", ( 0.76,  0.56,  0.56), 1.26, 1.26, 1.81 ,  1 , 0.81 ,  3 , 0.62 ),
80 (32,     "Germanium",       "Ge", (  0.4,  0.56,  0.56), 1.22, 1.22, 1.52 , -4 , 2.72 ,  2 , 0.73 ,  4 , 0.53 ),
81 (33,       "Arsenic",       "As", ( 0.74,  0.50,  0.89), 1.20, 1.20, 1.33 , -3 , 2.22 ,  3 , 0.58 ,  5 , 0.46 ),
82 (34,      "Selenium",       "Se", (  1.0,  0.63,   0.0), 1.16, 1.16, 1.22 , -2 , 1.91 , -1 , 2.32 ,  1 , 0.66 ,  4 , 0.50 ,  6 , 0.42 ),
83 (35,       "Bromine",       "Br", ( 0.65,  0.16,  0.16), 1.14, 1.14, 1.12 , -1 , 1.96 ,  5 , 0.47 ,  7 , 0.39 ),
84 (36,       "Krypton",       "Kr", ( 0.36,  0.72,  0.81), 1.31, 1.31, 1.24 ),
85 (37,      "Rubidium",       "Rb", ( 0.43,  0.18,  0.69), 2.16, 2.16, 2.98 ,  1 , 1.47 ),
86 (38,     "Strontium",       "Sr", (  0.0,   1.0,   0.0), 1.91, 1.91, 2.45 ,  2 , 1.12 ),
87 (39,       "Yttrium",        "Y", ( 0.58,   1.0,   1.0), 1.62, 1.62, 2.27 ,  3 , 0.89 ),
88 (40,     "Zirconium",       "Zr", ( 0.58,  0.87,  0.87), 1.45, 1.45, 2.16 ,  1 , 1.09 ,  4 , 0.79 ),
89 (41,       "Niobium",       "Nb", ( 0.45,  0.76,  0.78), 1.34, 1.34, 2.08 ,  1 , 1.00 ,  4 , 0.74 ,  5 , 0.69 ),
90 (42,    "Molybdenum",       "Mo", ( 0.32,  0.70,  0.70), 1.30, 1.30, 2.01 ,  1 , 0.93 ,  4 , 0.70 ,  6 , 0.62 ),
91 (43,    "Technetium",       "Tc", ( 0.23,  0.61,  0.61), 1.27, 1.27, 1.95 ,  7 , 0.97 ),
92 (44,     "Ruthenium",       "Ru", ( 0.14,  0.56,  0.56), 1.25, 1.25, 1.89 ,  4 , 0.67 ),
93 (45,       "Rhodium",       "Rh", ( 0.03,  0.49,  0.54), 1.25, 1.25, 1.83 ,  3 , 0.68 ),
94 (46,     "Palladium",       "Pd", (  0.0,  0.41,  0.52), 1.28, 1.28, 1.79 ,  2 , 0.80 ,  4 , 0.65 ),
95 (47,        "Silver",       "Ag", ( 0.75,  0.75,  0.75), 1.34, 1.34, 1.75 ,  1 , 1.26 ,  2 , 0.89 ),
96 (48,       "Cadmium",       "Cd", (  1.0,  0.85,  0.56), 1.48, 1.48, 1.71 ,  1 , 1.14 ,  2 , 0.97 ),
97 (49,        "Indium",       "In", ( 0.65,  0.45,  0.45), 1.44, 1.44, 2.00 ,  3 , 0.81 ),
98 (50,           "Tin",       "Sn", (  0.4,  0.50,  0.50), 1.41, 1.41, 1.72 , -4 , 2.94 , -1 , 3.70 ,  2 , 0.93 ,  4 , 0.71 ),
99 (51,      "Antimony",       "Sb", ( 0.61,  0.38,  0.70), 1.40, 1.40, 1.53 , -3 , 2.45 ,  3 , 0.76 ,  5 , 0.62 ),
100 (52,     "Tellurium",       "Te", ( 0.83,  0.47,   0.0), 1.36, 1.36, 1.42 , -2 , 2.11 , -1 , 2.50 ,  1 , 0.82 ,  4 , 0.70 ,  6 , 0.56 ),
101 (53,        "Iodine",        "I", ( 0.58,   0.0,  0.58), 1.33, 1.33, 1.32 , -1 , 2.20 ,  5 , 0.62 ,  7 , 0.50 ),
102 (54,         "Xenon",       "Xe", ( 0.25,  0.61,  0.69), 1.31, 1.31, 1.24 ),
103 (55,       "Caesium",       "Cs", ( 0.34,  0.09,  0.56), 2.35, 2.35, 3.35 ,  1 , 1.67 ),
104 (56,        "Barium",       "Ba", (  0.0,  0.78,   0.0), 1.98, 1.98, 2.78 ,  1 , 1.53 ,  2 , 1.34 ),
105 (57,     "Lanthanum",       "La", ( 0.43,  0.83,   1.0), 1.69, 1.69, 2.74 ,  1 , 1.39 ,  3 , 1.06 ),
106 (58,        "Cerium",       "Ce", (  1.0,   1.0,  0.78), 1.65, 1.65, 2.70 ,  1 , 1.27 ,  3 , 1.03 ,  4 , 0.92 ),
107 (59,  "Praseodymium",       "Pr", ( 0.85,   1.0,  0.78), 1.65, 1.65, 2.67 ,  3 , 1.01 ,  4 , 0.90 ),
108 (60,     "Neodymium",       "Nd", ( 0.78,   1.0,  0.78), 1.64, 1.64, 2.64 ,  3 , 0.99 ),
109 (61,    "Promethium",       "Pm", ( 0.63,   1.0,  0.78), 1.63, 1.63, 2.62 ,  3 , 0.97 ),
110 (62,      "Samarium",       "Sm", ( 0.56,   1.0,  0.78), 1.62, 1.62, 2.59 ,  3 , 0.96 ),
111 (63,      "Europium",       "Eu", ( 0.38,   1.0,  0.78), 1.85, 1.85, 2.56 ,  2 , 1.09 ,  3 , 0.95 ),
112 (64,    "Gadolinium",       "Gd", ( 0.27,   1.0,  0.78), 1.61, 1.61, 2.54 ,  3 , 0.93 ),
113 (65,       "Terbium",       "Tb", ( 0.18,   1.0,  0.78), 1.59, 1.59, 2.51 ,  3 , 0.92 ,  4 , 0.84 ),
114 (66,    "Dysprosium",       "Dy", ( 0.12,   1.0,  0.78), 1.59, 1.59, 2.49 ,  3 , 0.90 ),
115 (67,       "Holmium",       "Ho", (  0.0,   1.0,  0.61), 1.58, 1.58, 2.47 ,  3 , 0.89 ),
116 (68,        "Erbium",       "Er", (  0.0,  0.90,  0.45), 1.57, 1.57, 2.45 ,  3 , 0.88 ),
117 (69,       "Thulium",       "Tm", (  0.0,  0.83,  0.32), 1.56, 1.56, 2.42 ,  3 , 0.87 ),
118 (70,     "Ytterbium",       "Yb", (  0.0,  0.74,  0.21), 1.74, 1.74, 2.40 ,  2 , 0.93 ,  3 , 0.85 ),
119 (71,      "Lutetium",       "Lu", (  0.0,  0.67,  0.14), 1.56, 1.56, 2.25 ,  3 , 0.85 ),
120 (72,       "Hafnium",       "Hf", ( 0.30,  0.76,   1.0), 1.44, 1.44, 2.16 ,  4 , 0.78 ),
121 (73,      "Tantalum",       "Ta", ( 0.30,  0.65,   1.0), 1.34, 1.34, 2.09 ,  5 , 0.68 ),
122 (74,      "Tungsten",        "W", ( 0.12,  0.58,  0.83), 1.30, 1.30, 2.02 ,  4 , 0.70 ,  6 , 0.62 ),
123 (75,       "Rhenium",       "Re", ( 0.14,  0.49,  0.67), 1.28, 1.28, 1.97 ,  4 , 0.72 ,  7 , 0.56 ),
124 (76,        "Osmium",       "Os", ( 0.14,   0.4,  0.58), 1.26, 1.26, 1.92 ,  4 , 0.88 ,  6 , 0.69 ),
125 (77,       "Iridium",       "Ir", ( 0.09,  0.32,  0.52), 1.27, 1.27, 1.87 ,  4 , 0.68 ),
126 (78,     "Platinium",       "Pt", ( 0.81,  0.81,  0.87), 1.30, 1.30, 1.83 ,  2 , 0.80 ,  4 , 0.65 ),
127 (79,          "Gold",       "Au", (  1.0,  0.81,  0.13), 1.34, 1.34, 1.79 ,  1 , 1.37 ,  3 , 0.85 ),
128 (80,       "Mercury",       "Hg", ( 0.72,  0.72,  0.81), 1.49, 1.49, 1.76 ,  1 , 1.27 ,  2 , 1.10 ),
129 (81,      "Thallium",       "Tl", ( 0.65,  0.32,  0.30), 1.48, 1.48, 2.08 ,  1 , 1.47 ,  3 , 0.95 ),
130 (82,          "Lead",       "Pb", ( 0.34,  0.34,  0.38), 1.47, 1.47, 1.81 ,  2 , 1.20 ,  4 , 0.84 ),
131 (83,       "Bismuth",       "Bi", ( 0.61,  0.30,  0.70), 1.46, 1.46, 1.63 ,  1 , 0.98 ,  3 , 0.96 ,  5 , 0.74 ),
132 (84,      "Polonium",       "Po", ( 0.67,  0.36,   0.0), 1.46, 1.46, 1.53 ,  6 , 0.67 ),
133 (85,      "Astatine",       "At", ( 0.45,  0.30,  0.27), 1.45, 1.45, 1.43 , -3 , 2.22 ,  3 , 0.85 ,  5 , 0.46 ),
134 (86,         "Radon",       "Rn", ( 0.25,  0.50,  0.58), 1.00, 1.00, 1.34 ),
135 (87,      "Francium",       "Fr", ( 0.25,   0.0,   0.4), 1.00, 1.00, 1.00 ,  1 , 1.80 ),
136 (88,        "Radium",       "Ra", (  0.0,  0.49,   0.0), 1.00, 1.00, 1.00 ,  2 , 1.43 ),
137 (89,      "Actinium",       "Ac", ( 0.43,  0.67,  0.98), 1.00, 1.00, 1.00 ,  3 , 1.18 ),
138 (90,       "Thorium",       "Th", (  0.0,  0.72,   1.0), 1.65, 1.65, 1.00 ,  4 , 1.02 ),
139 (91,  "Protactinium",       "Pa", (  0.0,  0.63,   1.0), 1.00, 1.00, 1.00 ,  3 , 1.13 ,  4 , 0.98 ,  5 , 0.89 ),
140 (92,       "Uranium",        "U", (  0.0,  0.56,   1.0), 1.42, 1.42, 1.00 ,  4 , 0.97 ,  6 , 0.80 ),
141 (93,     "Neptunium",       "Np", (  0.0,  0.50,   1.0), 1.00, 1.00, 1.00 ,  3 , 1.10 ,  4 , 0.95 ,  7 , 0.71 ),
142 (94,     "Plutonium",       "Pu", (  0.0,  0.41,   1.0), 1.00, 1.00, 1.00 ,  3 , 1.08 ,  4 , 0.93 ),
143 (95,     "Americium",       "Am", ( 0.32,  0.36,  0.94), 1.00, 1.00, 1.00 ,  3 , 1.07 ,  4 , 0.92 ),
144 (96,        "Curium",       "Cm", ( 0.47,  0.36,  0.89), 1.00, 1.00, 1.00 ),
145 (97,     "Berkelium",       "Bk", ( 0.54,  0.30,  0.89), 1.00, 1.00, 1.00 ),
146 (98,   "Californium",       "Cf", ( 0.63,  0.21,  0.83), 1.00, 1.00, 1.00 ),
147 (99,   "Einsteinium",       "Es", ( 0.70,  0.12,  0.83), 1.00, 1.00, 1.00 ),
148 (100,       "Fermium",       "Fm", ( 0.70,  0.12,  0.72), 1.00, 1.00, 1.00 ),
149 (101,   "Mendelevium",       "Md", ( 0.70,  0.05,  0.65), 1.00, 1.00, 1.00 ),
150 (102,      "Nobelium",       "No", ( 0.74,  0.05,  0.52), 1.00, 1.00, 1.00 ),
151 (103,    "Lawrencium",       "Lr", ( 0.78,   0.0,   0.4), 1.00, 1.00, 1.00 ),
152 (104,       "Vacancy",      "Vac", (  0.5,   0.5,   0.5), 1.00, 1.00, 1.00),
153 (105,       "Default",  "Default", (  1.0,   1.0,   1.0), 1.00, 1.00, 1.00),
154 (106,         "Stick",    "Stick", (  0.5,   0.5,   0.5), 1.00, 1.00, 1.00),
155 )
156
157 # This list here contains all data of the elements and will be used during
158 # runtime. It is a list of classes.
159 # During executing Atomic Blender, the list will be initialized with the fixed
160 # data from above via the class structure below (ElementProp). We
161 # have then one fixed list (above), which will never be changed, and a list of
162 # classes with same data. The latter can be modified via loading a separate
163 # custom data file for instance.
164 ATOM_BLEND_ELEMENTS = []
165
166 # This is the class, which stores the properties for one element.
167 class ElementProp(object):
168     __slots__ = ('number', 'name', 'short_name', 'color', 'radii', 'radii_ionic')
169     def __init__(self, number, name, short_name, color, radii, radii_ionic):
170         self.number = number
171         self.name = name
172         self.short_name = short_name
173         self.color = color
174         self.radii = radii
175         self.radii_ionic = radii_ionic
176
177
178 # -----------------------------------------------------------------------------
179 #                                                          Some small routines
180
181
182 # This function measures the distance between two objects (atoms),
183 # which are active.
184 def distance():
185
186     if len(bpy.context.selected_bases) > 1:
187         object_1 = bpy.context.selected_objects[0]
188         object_2 = bpy.context.selected_objects[1]
189     else:
190         return "N.A."
191
192     dv = object_2.location - object_1.location
193     dist = str(dv.length)
194     pos = str.find(dist, ".")
195     dist = dist[:pos+4]
196     dist = dist + " A"
197   
198     return dist
199
200
201 def choose_objects(how, who, radius_all, radius_pm, radius_type):
202
203     if who == "ALL_IN_LAYER":
204
205         # Determine all selected layers.
206         layers = []
207         for i, layer in enumerate(bpy.context.scene.layers):
208             if layer == True:
209                 layers.append(i)
210                 
211         # Put all objects, which are in the layers, into a list.
212         change_objects = []
213         for obj in bpy.context.scene.objects:
214             for layer in layers:
215                 if obj.layers[layer] == True:
216                     change_objects.append(obj)
217                     
218         # Consider all objects, which are in the list 'change_objects'.
219         for obj in change_objects:
220             if len(obj.children) != 0:
221                 if obj.children[0].type in {'SURFACE', 'MESH'}:
222                     modify_objects(how, 
223                                    obj.children[0],
224                                    radius_all, 
225                                    radius_pm, 
226                                    radius_type)
227             else:
228                 if obj.type in {'SURFACE', 'MESH'}:
229                     modify_objects(how, 
230                                    obj,  
231                                    radius_all, 
232                                    radius_pm, 
233                                    radius_type)
234
235     if who == "ALL_ACTIVE":
236         for obj in bpy.context.selected_objects:
237             if len(obj.children) != 0:
238                 if obj.children[0].type in {'SURFACE', 'MESH'}:
239                     modify_objects(how, 
240                                    obj.children[0],
241                                    radius_all, 
242                                    radius_pm, 
243                                    radius_type)
244             else:
245                 if obj.type in {'SURFACE', 'MESH'}:
246                     modify_objects(how, 
247                                    obj,
248                                    radius_all, 
249                                    radius_pm, 
250                                    radius_type)
251
252
253
254 # Routine to modify the radii in picometer of a specific type of atom
255 def modify_objects(how, obj, radius_all, radius_pm, radius_type):
256
257     # Radius pm 
258     if how == "radius_pm":
259         if radius_pm[0] in obj.name:
260             obj.scale = (radius_pm[1]/100,) * 3
261             
262     # Radius all 
263     if how == "radius_all":
264         obj.scale *= radius_all      
265               
266     # Radius type 
267     if how == "radius_type":
268         for element in ATOM_BLEND_ELEMENTS:
269             if element.name in obj.name:
270                 obj.scale = (element.radii[int(radius_type)],) * 3
271
272
273 # Read the default element list.
274 def read_elements():
275
276     ATOM_BLEND_ELEMENTS[:] = []
277
278     for item in ATOM_BLEND_ELEMENTS_DEFAULT:
279
280         # All three radii into a list
281         radii = [item[4],item[5],item[6]]
282         # The handling of the ionic radii will be done later. So far, it is an
283         # empty list.
284         radii_ionic = []
285
286         li = ElementProp(item[0],item[1],item[2],item[3],
287                                      radii,radii_ionic)
288         ATOM_BLEND_ELEMENTS.append(li)
289
290
291 # Change color and radii by uisnf the list of elements.
292 def custom_datafile_change_atom_props():
293
294     for obj in bpy.context.selected_objects:
295         if len(obj.children) != 0:
296             child = obj.children[0]
297             if child.type in {'SURFACE', 'MESH'}:
298                 for element in ATOM_BLEND_ELEMENTS:
299                     if element.name in obj.name:
300                         child.scale = (element.radii[0],) * 3
301                         child.active_material.diffuse_color = element.color
302         else:
303             if obj.type in {'SURFACE', 'MESH'}:
304                 for element in ATOM_BLEND_ELEMENTS:
305                     if element.name in obj.name:
306                         obj.scale = (element.radii[0],) * 3
307                         obj.active_material.diffuse_color = element.color
308
309
310 # This reads a custom data file.
311 def custom_datafile(path_datafile):
312
313     if path_datafile == "":
314         return False
315
316     path_datafile = bpy.path.abspath(path_datafile)
317
318     if os.path.isfile(path_datafile) == False:
319         return False
320
321     # The whole list gets deleted! We build it new.
322     ATOM_BLEND_ELEMENTS[:] = []
323
324     # Read the data file, which contains all data
325     # (atom name, radii, colors, etc.)
326     data_file_p = io.open(path_datafile, "r")
327
328     for line in data_file_p:
329
330         if "Atom" in line:
331
332             line = data_file_p.readline()
333             # Number
334             line = data_file_p.readline()
335             number = line[19:-1]
336             # Name
337             line = data_file_p.readline()
338             name = line[19:-1]
339             # Short name
340             line = data_file_p.readline()
341             short_name = line[19:-1]
342             # Color
343             line = data_file_p.readline()
344             color_value = line[19:-1].split(',')
345             color = [float(color_value[0]),
346                      float(color_value[1]),
347                      float(color_value[2])]
348             # Used radius
349             line = data_file_p.readline()
350             radius_used = float(line[19:-1])
351             # Atomic radius
352             line = data_file_p.readline()
353             radius_atomic = float(line[19:-1])
354             # Van der Waals radius
355             line = data_file_p.readline()
356             radius_vdW = float(line[19:-1])
357             radii = [radius_used,radius_atomic,radius_vdW]
358             radii_ionic = []
359
360             element = ElementProp(number,name,short_name,color,
361                                               radii, radii_ionic)
362
363             ATOM_BLEND_ELEMENTS.append(element)
364
365     data_file_p.close()
366
367     return True
368
369
370
371 # Routine for separating atoms from a dupliverts strucutre.
372 def separate_atoms(scn):
373
374     # Get first all important properties from the atoms, which the user
375     # has chosen: location, color, scale
376     obj = bpy.context.edit_object
377         
378     # Do nothing if it is not a dupliverts structure.
379     if not obj.dupli_type == "VERTS":
380        return {'FINISHED'}
381         
382     bm = bmesh.from_edit_mesh(obj.data)
383
384     locations = []
385
386     for v in bm.verts:
387         if v.select:
388             locations.append(obj.matrix_world * v.co)
389
390     bm.free()
391     del(bm)
392
393     name  = obj.name
394     scale = obj.children[0].scale
395     material = obj.children[0].active_material
396
397     # Separate the vertex from the main mesh and create a new mesh.
398     bpy.ops.mesh.separate()
399     new_object = bpy.context.scene.objects[0]
400     # And now, switch to the OBJECT mode such that we can ...
401     bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
402     # ... delete the new mesh including the separated vertex
403     bpy.ops.object.select_all(action='DESELECT')
404     new_object.select = True
405     bpy.ops.object.delete()  
406
407     # Create new atoms/vacancies at the position of the old atoms
408     current_layers=bpy.context.scene.layers
409
410     # For all selected positions do:
411     for location in locations:
412         # For any ball do ...
413         if "Vacancy" not in name:
414             # NURBS ball
415             if obj.children[0].type == "SURFACE":
416                 bpy.ops.surface.primitive_nurbs_surface_sphere_add(
417                                 view_align=False, enter_editmode=False,
418                                 location=location,
419                                 rotation=(0.0, 0.0, 0.0),
420                                 layers=current_layers)
421             # Mesh ball                    
422             elif obj.children[0].type == "MESH":
423                 bpy.ops.mesh.primitive_uv_sphere_add(
424                                 segments=32,
425                                 ring_count=32,                    
426                                 #segments=scn.mesh_azimuth,
427                                 #ring_count=scn.mesh_zenith,
428                                 size=1, view_align=False, enter_editmode=False,
429                                 location=location,
430                                 rotation=(0, 0, 0),
431                                 layers=current_layers)
432         # If it is a vacancy create a cube ...                    
433         else:
434             bpy.ops.mesh.primitive_cube_add(
435                            view_align=False, enter_editmode=False,
436                            location=location,
437                            rotation=(0.0, 0.0, 0.0),
438                            layers=current_layers)
439                                
440         new_atom = bpy.context.scene.objects.active
441         # Scale, material and name it.
442         new_atom.scale = scale
443         new_atom.active_material = material
444         new_atom.name = name + "_sep"
445         new_atom.select = True
446
447     bpy.context.scene.objects.active = obj
448     #bpy.ops.object.select_all(action='DESELECT')