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