Cleanup: simplify file name incrementing logic
[blender-addons.git] / io_mesh_atomic / utility_panel.py
blobf41b8408a6bedaac50846950b235dd0b284d2ec6
1 # ##### BEGIN GPL LICENSE BLOCK #####
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.
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.
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.
17 # ##### END GPL LICENSE BLOCK #####
19 import os
20 import bpy
21 import bmesh
22 from mathutils import Vector
23 from math import sqrt
24 from copy import copy
26 # -----------------------------------------------------------------------------
27 # Atom and element data
30 # This is a list that contains some data of all possible elements. The structure
31 # is as follows:
33 # 1, "Hydrogen", "H", [0.0,0.0,1.0], 0.32, 0.32, 0.32 , -1 , 1.54 means
35 # No., name, short name, color, radius (used), radius (covalent), radius (atomic),
37 # charge state 1, radius (ionic) 1, charge state 2, radius (ionic) 2, ... all
38 # charge states for any atom are listed, if existing.
39 # The list is fixed and cannot be changed ... (see below)
41 ELEMENTS_DEFAULT = (
42 ( 1, "Hydrogen", "H", ( 1.0, 1.0, 1.0, 1.0), 0.32, 0.32, 0.79 , -1 , 1.54 ),
43 ( 2, "Helium", "He", ( 0.85, 1.0, 1.0, 1.0), 0.93, 0.93, 0.49 ),
44 ( 3, "Lithium", "Li", ( 0.8, 0.50, 1.0, 1.0), 1.23, 1.23, 2.05 , 1 , 0.68 ),
45 ( 4, "Beryllium", "Be", ( 0.76, 1.0, 0.0, 1.0), 0.90, 0.90, 1.40 , 1 , 0.44 , 2 , 0.35 ),
46 ( 5, "Boron", "B", ( 1.0, 0.70, 0.70, 1.0), 0.82, 0.82, 1.17 , 1 , 0.35 , 3 , 0.23 ),
47 ( 6, "Carbon", "C", ( 0.56, 0.56, 0.56, 1.0), 0.77, 0.77, 0.91 , -4 , 2.60 , 4 , 0.16 ),
48 ( 7, "Nitrogen", "N", ( 0.18, 0.31, 0.97, 1.0), 0.75, 0.75, 0.75 , -3 , 1.71 , 1 , 0.25 , 3 , 0.16 , 5 , 0.13 ),
49 ( 8, "Oxygen", "O", ( 1.0, 0.05, 0.05, 1.0), 0.73, 0.73, 0.65 , -2 , 1.32 , -1 , 1.76 , 1 , 0.22 , 6 , 0.09 ),
50 ( 9, "Fluorine", "F", ( 0.56, 0.87, 0.31, 1.0), 0.72, 0.72, 0.57 , -1 , 1.33 , 7 , 0.08 ),
51 (10, "Neon", "Ne", ( 0.70, 0.89, 0.96, 1.0), 0.71, 0.71, 0.51 , 1 , 1.12 ),
52 (11, "Sodium", "Na", ( 0.67, 0.36, 0.94, 1.0), 1.54, 1.54, 2.23 , 1 , 0.97 ),
53 (12, "Magnesium", "Mg", ( 0.54, 1.0, 0.0, 1.0), 1.36, 1.36, 1.72 , 1 , 0.82 , 2 , 0.66 ),
54 (13, "Aluminium", "Al", ( 0.74, 0.65, 0.65, 1.0), 1.18, 1.18, 1.82 , 3 , 0.51 ),
55 (14, "Silicon", "Si", ( 0.94, 0.78, 0.62, 1.0), 1.11, 1.11, 1.46 , -4 , 2.71 , -1 , 3.84 , 1 , 0.65 , 4 , 0.42 ),
56 (15, "Phosphorus", "P", ( 1.0, 0.50, 0.0, 1.0), 1.06, 1.06, 1.23 , -3 , 2.12 , 3 , 0.44 , 5 , 0.35 ),
57 (16, "Sulfur", "S", ( 1.0, 1.0, 0.18, 1.0), 1.02, 1.02, 1.09 , -2 , 1.84 , 2 , 2.19 , 4 , 0.37 , 6 , 0.30 ),
58 (17, "Chlorine", "Cl", ( 0.12, 0.94, 0.12, 1.0), 0.99, 0.99, 0.97 , -1 , 1.81 , 5 , 0.34 , 7 , 0.27 ),
59 (18, "Argon", "Ar", ( 0.50, 0.81, 0.89, 1.0), 0.98, 0.98, 0.88 , 1 , 1.54 ),
60 (19, "Potassium", "K", ( 0.56, 0.25, 0.83, 1.0), 2.03, 2.03, 2.77 , 1 , 0.81 ),
61 (20, "Calcium", "Ca", ( 0.23, 1.0, 0.0, 1.0), 1.74, 1.74, 2.23 , 1 , 1.18 , 2 , 0.99 ),
62 (21, "Scandium", "Sc", ( 0.90, 0.90, 0.90, 1.0), 1.44, 1.44, 2.09 , 3 , 0.73 ),
63 (22, "Titanium", "Ti", ( 0.74, 0.76, 0.78, 1.0), 1.32, 1.32, 2.00 , 1 , 0.96 , 2 , 0.94 , 3 , 0.76 , 4 , 0.68 ),
64 (23, "Vanadium", "V", ( 0.65, 0.65, 0.67, 1.0), 1.22, 1.22, 1.92 , 2 , 0.88 , 3 , 0.74 , 4 , 0.63 , 5 , 0.59 ),
65 (24, "Chromium", "Cr", ( 0.54, 0.6, 0.78, 1.0), 1.18, 1.18, 1.85 , 1 , 0.81 , 2 , 0.89 , 3 , 0.63 , 6 , 0.52 ),
66 (25, "Manganese", "Mn", ( 0.61, 0.47, 0.78, 1.0), 1.17, 1.17, 1.79 , 2 , 0.80 , 3 , 0.66 , 4 , 0.60 , 7 , 0.46 ),
67 (26, "Iron", "Fe", ( 0.87, 0.4, 0.2, 1.0), 1.17, 1.17, 1.72 , 2 , 0.74 , 3 , 0.64 ),
68 (27, "Cobalt", "Co", ( 0.94, 0.56, 0.62, 1.0), 1.16, 1.16, 1.67 , 2 , 0.72 , 3 , 0.63 ),
69 (28, "Nickel", "Ni", ( 0.31, 0.81, 0.31, 1.0), 1.15, 1.15, 1.62 , 2 , 0.69 ),
70 (29, "Copper", "Cu", ( 0.78, 0.50, 0.2, 1.0), 1.17, 1.17, 1.57 , 1 , 0.96 , 2 , 0.72 ),
71 (30, "Zinc", "Zn", ( 0.49, 0.50, 0.69, 1.0), 1.25, 1.25, 1.53 , 1 , 0.88 , 2 , 0.74 ),
72 (31, "Gallium", "Ga", ( 0.76, 0.56, 0.56, 1.0), 1.26, 1.26, 1.81 , 1 , 0.81 , 3 , 0.62 ),
73 (32, "Germanium", "Ge", ( 0.4, 0.56, 0.56, 1.0), 1.22, 1.22, 1.52 , -4 , 2.72 , 2 , 0.73 , 4 , 0.53 ),
74 (33, "Arsenic", "As", ( 0.74, 0.50, 0.89, 1.0), 1.20, 1.20, 1.33 , -3 , 2.22 , 3 , 0.58 , 5 , 0.46 ),
75 (34, "Selenium", "Se", ( 1.0, 0.63, 0.0, 1.0), 1.16, 1.16, 1.22 , -2 , 1.91 , -1 , 2.32 , 1 , 0.66 , 4 , 0.50 , 6 , 0.42 ),
76 (35, "Bromine", "Br", ( 0.65, 0.16, 0.16, 1.0), 1.14, 1.14, 1.12 , -1 , 1.96 , 5 , 0.47 , 7 , 0.39 ),
77 (36, "Krypton", "Kr", ( 0.36, 0.72, 0.81, 1.0), 1.31, 1.31, 1.24 ),
78 (37, "Rubidium", "Rb", ( 0.43, 0.18, 0.69, 1.0), 2.16, 2.16, 2.98 , 1 , 1.47 ),
79 (38, "Strontium", "Sr", ( 0.0, 1.0, 0.0, 1.0), 1.91, 1.91, 2.45 , 2 , 1.12 ),
80 (39, "Yttrium", "Y", ( 0.58, 1.0, 1.0, 1.0), 1.62, 1.62, 2.27 , 3 , 0.89 ),
81 (40, "Zirconium", "Zr", ( 0.58, 0.87, 0.87, 1.0), 1.45, 1.45, 2.16 , 1 , 1.09 , 4 , 0.79 ),
82 (41, "Niobium", "Nb", ( 0.45, 0.76, 0.78, 1.0), 1.34, 1.34, 2.08 , 1 , 1.00 , 4 , 0.74 , 5 , 0.69 ),
83 (42, "Molybdenum", "Mo", ( 0.32, 0.70, 0.70, 1.0), 1.30, 1.30, 2.01 , 1 , 0.93 , 4 , 0.70 , 6 , 0.62 ),
84 (43, "Technetium", "Tc", ( 0.23, 0.61, 0.61, 1.0), 1.27, 1.27, 1.95 , 7 , 0.97 ),
85 (44, "Ruthenium", "Ru", ( 0.14, 0.56, 0.56, 1.0), 1.25, 1.25, 1.89 , 4 , 0.67 ),
86 (45, "Rhodium", "Rh", ( 0.03, 0.49, 0.54, 1.0), 1.25, 1.25, 1.83 , 3 , 0.68 ),
87 (46, "Palladium", "Pd", ( 0.0, 0.41, 0.52, 1.0), 1.28, 1.28, 1.79 , 2 , 0.80 , 4 , 0.65 ),
88 (47, "Silver", "Ag", ( 0.75, 0.75, 0.75, 1.0), 1.34, 1.34, 1.75 , 1 , 1.26 , 2 , 0.89 ),
89 (48, "Cadmium", "Cd", ( 1.0, 0.85, 0.56, 1.0), 1.48, 1.48, 1.71 , 1 , 1.14 , 2 , 0.97 ),
90 (49, "Indium", "In", ( 0.65, 0.45, 0.45, 1.0), 1.44, 1.44, 2.00 , 3 , 0.81 ),
91 (50, "Tin", "Sn", ( 0.4, 0.50, 0.50, 1.0), 1.41, 1.41, 1.72 , -4 , 2.94 , -1 , 3.70 , 2 , 0.93 , 4 , 0.71 ),
92 (51, "Antimony", "Sb", ( 0.61, 0.38, 0.70, 1.0), 1.40, 1.40, 1.53 , -3 , 2.45 , 3 , 0.76 , 5 , 0.62 ),
93 (52, "Tellurium", "Te", ( 0.83, 0.47, 0.0, 1.0), 1.36, 1.36, 1.42 , -2 , 2.11 , -1 , 2.50 , 1 , 0.82 , 4 , 0.70 , 6 , 0.56 ),
94 (53, "Iodine", "I", ( 0.58, 0.0, 0.58, 1.0), 1.33, 1.33, 1.32 , -1 , 2.20 , 5 , 0.62 , 7 , 0.50 ),
95 (54, "Xenon", "Xe", ( 0.25, 0.61, 0.69, 1.0), 1.31, 1.31, 1.24 ),
96 (55, "Caesium", "Cs", ( 0.34, 0.09, 0.56, 1.0), 2.35, 2.35, 3.35 , 1 , 1.67 ),
97 (56, "Barium", "Ba", ( 0.0, 0.78, 0.0, 1.0), 1.98, 1.98, 2.78 , 1 , 1.53 , 2 , 1.34 ),
98 (57, "Lanthanum", "La", ( 0.43, 0.83, 1.0, 1.0), 1.69, 1.69, 2.74 , 1 , 1.39 , 3 , 1.06 ),
99 (58, "Cerium", "Ce", ( 1.0, 1.0, 0.78, 1.0), 1.65, 1.65, 2.70 , 1 , 1.27 , 3 , 1.03 , 4 , 0.92 ),
100 (59, "Praseodymium", "Pr", ( 0.85, 1.0, 0.78, 1.0), 1.65, 1.65, 2.67 , 3 , 1.01 , 4 , 0.90 ),
101 (60, "Neodymium", "Nd", ( 0.78, 1.0, 0.78, 1.0), 1.64, 1.64, 2.64 , 3 , 0.99 ),
102 (61, "Promethium", "Pm", ( 0.63, 1.0, 0.78, 1.0), 1.63, 1.63, 2.62 , 3 , 0.97 ),
103 (62, "Samarium", "Sm", ( 0.56, 1.0, 0.78, 1.0), 1.62, 1.62, 2.59 , 3 , 0.96 ),
104 (63, "Europium", "Eu", ( 0.38, 1.0, 0.78, 1.0), 1.85, 1.85, 2.56 , 2 , 1.09 , 3 , 0.95 ),
105 (64, "Gadolinium", "Gd", ( 0.27, 1.0, 0.78, 1.0), 1.61, 1.61, 2.54 , 3 , 0.93 ),
106 (65, "Terbium", "Tb", ( 0.18, 1.0, 0.78, 1.0), 1.59, 1.59, 2.51 , 3 , 0.92 , 4 , 0.84 ),
107 (66, "Dysprosium", "Dy", ( 0.12, 1.0, 0.78, 1.0), 1.59, 1.59, 2.49 , 3 , 0.90 ),
108 (67, "Holmium", "Ho", ( 0.0, 1.0, 0.61, 1.0), 1.58, 1.58, 2.47 , 3 , 0.89 ),
109 (68, "Erbium", "Er", ( 0.0, 0.90, 0.45, 1.0), 1.57, 1.57, 2.45 , 3 , 0.88 ),
110 (69, "Thulium", "Tm", ( 0.0, 0.83, 0.32, 1.0), 1.56, 1.56, 2.42 , 3 , 0.87 ),
111 (70, "Ytterbium", "Yb", ( 0.0, 0.74, 0.21, 1.0), 1.74, 1.74, 2.40 , 2 , 0.93 , 3 , 0.85 ),
112 (71, "Lutetium", "Lu", ( 0.0, 0.67, 0.14, 1.0), 1.56, 1.56, 2.25 , 3 , 0.85 ),
113 (72, "Hafnium", "Hf", ( 0.30, 0.76, 1.0, 1.0), 1.44, 1.44, 2.16 , 4 , 0.78 ),
114 (73, "Tantalum", "Ta", ( 0.30, 0.65, 1.0, 1.0), 1.34, 1.34, 2.09 , 5 , 0.68 ),
115 (74, "Tungsten", "W", ( 0.12, 0.58, 0.83, 1.0), 1.30, 1.30, 2.02 , 4 , 0.70 , 6 , 0.62 ),
116 (75, "Rhenium", "Re", ( 0.14, 0.49, 0.67, 1.0), 1.28, 1.28, 1.97 , 4 , 0.72 , 7 , 0.56 ),
117 (76, "Osmium", "Os", ( 0.14, 0.4, 0.58, 1.0), 1.26, 1.26, 1.92 , 4 , 0.88 , 6 , 0.69 ),
118 (77, "Iridium", "Ir", ( 0.09, 0.32, 0.52, 1.0), 1.27, 1.27, 1.87 , 4 , 0.68 ),
119 (78, "Platinum", "Pt", ( 0.81, 0.81, 0.87, 1.0), 1.30, 1.30, 1.83 , 2 , 0.80 , 4 , 0.65 ),
120 (79, "Gold", "Au", ( 1.0, 0.81, 0.13, 1.0), 1.34, 1.34, 1.79 , 1 , 1.37 , 3 , 0.85 ),
121 (80, "Mercury", "Hg", ( 0.72, 0.72, 0.81, 1.0), 1.49, 1.49, 1.76 , 1 , 1.27 , 2 , 1.10 ),
122 (81, "Thallium", "Tl", ( 0.65, 0.32, 0.30, 1.0), 1.48, 1.48, 2.08 , 1 , 1.47 , 3 , 0.95 ),
123 (82, "Lead", "Pb", ( 0.34, 0.34, 0.38, 1.0), 1.47, 1.47, 1.81 , 2 , 1.20 , 4 , 0.84 ),
124 (83, "Bismuth", "Bi", ( 0.61, 0.30, 0.70, 1.0), 1.46, 1.46, 1.63 , 1 , 0.98 , 3 , 0.96 , 5 , 0.74 ),
125 (84, "Polonium", "Po", ( 0.67, 0.36, 0.0, 1.0), 1.46, 1.46, 1.53 , 6 , 0.67 ),
126 (85, "Astatine", "At", ( 0.45, 0.30, 0.27, 1.0), 1.45, 1.45, 1.43 , -3 , 2.22 , 3 , 0.85 , 5 , 0.46 ),
127 (86, "Radon", "Rn", ( 0.25, 0.50, 0.58, 1.0), 1.00, 1.00, 1.34 ),
128 (87, "Francium", "Fr", ( 0.25, 0.0, 0.4, 1.0), 1.00, 1.00, 1.00 , 1 , 1.80 ),
129 (88, "Radium", "Ra", ( 0.0, 0.49, 0.0, 1.0), 1.00, 1.00, 1.00 , 2 , 1.43 ),
130 (89, "Actinium", "Ac", ( 0.43, 0.67, 0.98, 1.0), 1.00, 1.00, 1.00 , 3 , 1.18 ),
131 (90, "Thorium", "Th", ( 0.0, 0.72, 1.0, 1.0), 1.65, 1.65, 1.00 , 4 , 1.02 ),
132 (91, "Protactinium", "Pa", ( 0.0, 0.63, 1.0, 1.0), 1.00, 1.00, 1.00 , 3 , 1.13 , 4 , 0.98 , 5 , 0.89 ),
133 (92, "Uranium", "U", ( 0.0, 0.56, 1.0, 1.0), 1.42, 1.42, 1.00 , 4 , 0.97 , 6 , 0.80 ),
134 (93, "Neptunium", "Np", ( 0.0, 0.50, 1.0, 1.0), 1.00, 1.00, 1.00 , 3 , 1.10 , 4 , 0.95 , 7 , 0.71 ),
135 (94, "Plutonium", "Pu", ( 0.0, 0.41, 1.0, 1.0), 1.00, 1.00, 1.00 , 3 , 1.08 , 4 , 0.93 ),
136 (95, "Americium", "Am", ( 0.32, 0.36, 0.94, 1.0), 1.00, 1.00, 1.00 , 3 , 1.07 , 4 , 0.92 ),
137 (96, "Curium", "Cm", ( 0.47, 0.36, 0.89, 1.0), 1.00, 1.00, 1.00 ),
138 (97, "Berkelium", "Bk", ( 0.54, 0.30, 0.89, 1.0), 1.00, 1.00, 1.00 ),
139 (98, "Californium", "Cf", ( 0.63, 0.21, 0.83, 1.0), 1.00, 1.00, 1.00 ),
140 (99, "Einsteinium", "Es", ( 0.70, 0.12, 0.83, 1.0), 1.00, 1.00, 1.00 ),
141 (100, "Fermium", "Fm", ( 0.70, 0.12, 0.72, 1.0), 1.00, 1.00, 1.00 ),
142 (101, "Mendelevium", "Md", ( 0.70, 0.05, 0.65, 1.0), 1.00, 1.00, 1.00 ),
143 (102, "Nobelium", "No", ( 0.74, 0.05, 0.52, 1.0), 1.00, 1.00, 1.00 ),
144 (103, "Lawrencium", "Lr", ( 0.78, 0.0, 0.4, 1.0), 1.00, 1.00, 1.00 ),
145 (104, "Vacancy", "Vac", ( 0.5, 0.5, 0.5, 1.0), 1.00, 1.00, 1.00),
146 (105, "Default", "Default", ( 1.0, 1.0, 1.0, 1.0), 1.00, 1.00, 1.00),
147 (106, "Stick", "Stick", ( 0.5, 0.5, 0.5, 1.0), 1.00, 1.00, 1.00),
150 # The list 'ELEMENTS' contains all data of the elements and will be used during
151 # runtime. The list will be initialized with the fixed
152 # data from above via the class below (ElementProp). One fixed list (above),
153 # which cannot be changed, and a list of classes with same data (ELEMENTS) exist.
154 # The list 'ELEMENTS' can be modified by e.g. loading a separate custom
155 # data file.
156 ELEMENTS = []
159 # This is the class, which stores the properties for one element.
160 class ElementProp(object):
161 __slots__ = ('number', 'name', 'short_name', 'color', 'radii', 'radii_ionic')
162 def __init__(self, number, name, short_name, color, radii, radii_ionic):
163 self.number = number
164 self.name = name
165 self.short_name = short_name
166 self.color = color
167 self.radii = radii
168 self.radii_ionic = radii_ionic
171 # This function measures the distance between two selected objects.
172 def distance():
174 # In the 'EDIT' mode
175 if bpy.context.mode == 'EDIT_MESH':
177 atom = bpy.context.edit_object
178 bm = bmesh.from_edit_mesh(atom.data)
179 locations = []
181 for v in bm.verts:
182 if v.select:
183 locations.append(atom.matrix_world @ v.co)
185 if len(locations) > 1:
186 location1 = locations[0]
187 location2 = locations[1]
188 else:
189 return "N.A"
190 # In the 'OBJECT' mode
191 else:
193 if len(bpy.context.selected_objects) > 1:
194 location1 = bpy.context.selected_objects[0].location
195 location2 = bpy.context.selected_objects[1].location
196 else:
197 return "N.A."
199 dv = location2 - location1
200 dist = str(dv.length)
201 pos = str.find(dist, ".")
202 dist = dist[:pos+4]
203 dist = dist + " A"
205 return dist
208 def choose_objects(action_type,
209 who,
210 radius_all,
211 radius_pm,
212 radius_type,
213 radius_type_ionic,
214 sticks_all):
216 # For selected objects of all selected layers
217 if who == "ALL_IN_LAYER":
218 # Determine all selected layers.
219 layers = []
220 for i, layer in enumerate(bpy.context.scene.layers):
221 if layer == True:
222 layers.append(i)
224 # Put all objects, which are in the layers, into a list.
225 change_objects_all = []
226 for atom in bpy.context.scene.objects:
227 for layer in layers:
228 if atom.layers[layer] == True:
229 change_objects_all.append(atom)
230 # For selected objects of the visible layer
231 elif who == "ALL_ACTIVE":
232 change_objects_all = []
233 # Note all selected objects first.
234 for atom in bpy.context.selected_objects:
235 change_objects_all.append(atom)
237 # This is very important now: If there are dupliverts structures, note
238 # only the parents and NOT the children! Otherwise the double work is
239 # done or the system can even crash if objects are deleted. - The
240 # chidlren are accessed anyways (see below).
241 change_objects = []
242 for atom in change_objects_all:
243 if atom.parent != None:
244 FLAG = False
245 for atom2 in change_objects:
246 if atom2 == atom.parent:
247 FLAG = True
248 if FLAG == False:
249 change_objects.append(atom)
250 else:
251 change_objects.append(atom)
253 # And now, consider all objects, which are in the list 'change_objects'.
254 for atom in change_objects:
255 if len(atom.children) != 0:
256 for atom_child in atom.children:
257 if atom_child.type in {'SURFACE', 'MESH', 'META'}:
258 modify_objects(action_type,
259 atom_child,
260 radius_all,
261 radius_pm,
262 radius_type,
263 radius_type_ionic,
264 sticks_all)
265 else:
266 if atom.type in {'SURFACE', 'MESH', 'META'}:
267 modify_objects(action_type,
268 atom,
269 radius_all,
270 radius_pm,
271 radius_type,
272 radius_type_ionic,
273 sticks_all)
276 # Modifying the radius of a selected atom or stick
277 def modify_objects(action_type,
278 atom,
279 radius_all,
280 radius_pm,
281 radius_type,
282 radius_type_ionic,
283 sticks_all):
285 # Modify atom radius (in pm)
286 if action_type == "ATOM_RADIUS_PM" and "STICK" not in atom.name.upper():
287 if radius_pm[0] in atom.name:
288 atom.scale = (radius_pm[1]/100,) * 3
290 # Modify atom radius (all selected)
291 if action_type == "ATOM_RADIUS_ALL" and "STICK" not in atom.name.upper():
292 atom.scale *= radius_all
294 # Modify atom radius (type, van der Waals, atomic or ionic)
295 if action_type == "ATOM_RADIUS_TYPE" and "STICK" not in atom.name.upper():
296 for element in ELEMENTS:
297 if element.name in atom.name:
298 # For ionic radii
299 if radius_type == '3':
300 charge_states = element.radii_ionic[::2]
301 charge_radii = element.radii_ionic[1::2]
302 charge_state_chosen = int(radius_type_ionic) - 4
304 find = (lambda searchList, elem:
305 [[i for i, x in enumerate(searchList) if x == e]
306 for e in elem])
307 index = find(charge_states,[charge_state_chosen])[0]
309 # Is there a charge state?
310 if index != []:
311 atom.scale = (charge_radii[index[0]],) * 3
313 # For atomic and van der Waals radii.
314 else:
315 atom.scale = (element.radii[int(radius_type)],) * 3
317 # Modify atom sticks
318 if (action_type == "STICKS_RADIUS_ALL" and 'STICK' in atom.name.upper() and
319 ('CUP' in atom.name.upper() or
320 'CYLINDER' in atom.name.upper())):
322 # For dupliverts structures only: Make the cylinder or cup visible
323 # first, otherwise one cannot go into EDIT mode. Note that 'atom' here
324 # is in fact a 'stick' (cylinder or cup).
325 # First, identify if it is a normal cylinder object or a dupliverts
326 # structure. The identifier for a dupliverts structure is the parent's
327 # name, which includes "_sticks_mesh"
328 if "_sticks_mesh" in atom.parent.name:
329 atom.hide_set(False)
331 bpy.context.view_layer.objects.active = atom
332 bpy.ops.object.mode_set(mode='EDIT', toggle=False)
333 bm = bmesh.from_edit_mesh(atom.data)
335 locations = []
336 for v in bm.verts:
337 locations.append(v.co)
339 center = Vector((0.0,0.0,0.0))
340 center = sum([location for location in locations], center)/len(locations)
342 radius = sum([(loc[0]-center[0])**2+(loc[1]-center[1])**2
343 for loc in locations], 0)
344 radius_new = radius * sticks_all
346 for v in bm.verts:
347 v.co[0] = ((v.co[0] - center[0]) / radius) * radius_new + center[0]
348 v.co[1] = ((v.co[1] - center[1]) / radius) * radius_new + center[1]
350 bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
351 # Hide again the representative stick (cylinder or cup) if it is a
352 # dupliverts structure.
353 if "_sticks_mesh" in atom.parent.name:
354 atom.hide_set(True)
356 bpy.context.view_layer.objects.active = None
358 # Replace atom objects
359 if action_type == "ATOM_REPLACE_OBJ" and "STICK" not in atom.name.upper():
361 scn = bpy.context.scene.atom_blend
363 new_material = draw_obj_material(scn.replace_objs_material,
364 atom.active_material)
366 # Special object (like halo, etc.)
367 if scn.replace_objs_special != '0':
368 new_atom = draw_obj_special(scn.replace_objs_special, atom)
369 # Standard geometrical objects
370 else:
371 # If the atom shape shall not be changed, then:
372 if scn.replace_objs == '0':
373 atom.active_material = new_material
374 #return {'FINISHED'}
375 # If the atom shape shall change, then:
376 else:
377 new_atom = draw_obj(scn.replace_objs, atom, new_material)
379 # Default shapes and colors for atoms
380 if action_type == "ATOM_DEFAULT_OBJ" and "STICK" not in atom.name.upper():
382 scn = bpy.context.scene.atom_blend
384 # Create new material
385 new_material = bpy.data.materials.new("tmp")
386 # Create new object (NURBS sphere = '1b')
387 new_atom = draw_obj('1b', atom, new_material)
388 new_atom.active_material = new_material
389 new_material = draw_obj_material('0', new_material)
391 # Change size and color of the new object
392 for element in ELEMENTS:
393 if element.name in new_atom.name:
394 new_atom.scale = (element.radii[0],) * 3
395 new_atom.active_material.diffuse_color = element.color
396 new_atom.name = element.name + "_ball"
397 new_atom.active_material.name = element.name
398 break
401 # Separating atoms from a dupliverts structure.
402 def separate_atoms(scn):
404 # Get the mesh.
405 mesh = bpy.context.edit_object
407 # Do nothing if it is not a dupliverts structure.
408 if not mesh.instance_type == "VERTS":
409 return {'FINISHED'}
411 # This is the name of the mesh
412 mesh_name = mesh.name
413 # Get the collection
414 coll = mesh.users_collection[0]
416 # Get the coordinates of the selected vertices (atoms)
417 bm = bmesh.from_edit_mesh(mesh.data)
418 locations = []
419 for v in bm.verts:
420 if v.select:
421 locations.append(mesh.matrix_world @ v.co)
423 # Free memory
424 bm.free()
425 del(bm)
427 # Delete already the selected vertices
428 bpy.ops.mesh.delete(type='VERT')
430 # Find the representative ball within the collection.
431 for obj in coll.objects:
432 if obj.parent != None:
433 if obj.parent.name == mesh_name:
434 break
436 # Create balls and put them at the places where the vertices (atoms) have
437 # been before.
438 for location in locations:
439 obj_dupli = obj.copy()
440 obj_dupli.data = obj.data.copy()
441 obj_dupli.parent = None
442 coll.objects.link(obj_dupli)
443 obj_dupli.location = location
444 obj_dupli.name = obj.name + "_sep"
445 # Do not hide the object!
446 obj_dupli.hide_set(False)
449 bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
450 bpy.context.view_layer.objects.active = mesh
453 # Prepare a new material
454 def draw_obj_material(material_type, material):
456 if material_type == '0': # Unchanged
457 material_new = material
458 if material_type == '1': # Normal
459 material_new = bpy.data.materials.new(material.name + "_normal")
460 if material_type == '2': # Transparent
461 material_new = bpy.data.materials.new(material.name + "_transparent")
462 material_new.metallic = 0.8
463 material_new.specular_intensity = 0.5
464 material_new.roughness = 0.3
465 material_new.blend_method = 'OPAQUE'
466 material_new.show_transparent_back = False
467 # Some properties for cycles
468 material_new.use_nodes = True
469 mat_P_BSDF = material_new.node_tree.nodes['Principled BSDF']
470 mat_P_BSDF.inputs['Metallic'].default_value = 0.1
471 mat_P_BSDF.inputs['Roughness'].default_value = 0.2
472 mat_P_BSDF.inputs['Transmission'].default_value = 0.9
473 mat_P_BSDF.inputs['IOR'].default_value = 0.8
474 if material_type == '3': # Reflecting
475 material_new = bpy.data.materials.new(material.name + "_reflecting")
476 material_new.metallic = 0.5
477 material_new.specular_intensity = 0.5
478 material_new.roughness = 0.0
479 material_new.blend_method = 'OPAQUE'
480 # Some properties for cycles
481 material_new.use_nodes = True
482 mat_P_BSDF = material_new.node_tree.nodes['Principled BSDF']
483 mat_P_BSDF.inputs['Metallic'].default_value = 0.95
484 mat_P_BSDF.inputs['Roughness'].default_value = 0.1
485 mat_P_BSDF.inputs['Transmission'].default_value = 0.0
486 mat_P_BSDF.inputs['IOR'].default_value = 1.0
487 if material_type == '4': # Transparent + reflecting
488 material_new = bpy.data.materials.new(material.name + "_trans+refl")
489 material_new.metallic = 0.3
490 material_new.specular_intensity = 0.5
491 material_new.roughness = 0.3
492 material_new.blend_method = 'OPAQUE'
493 material_new.show_transparent_back = False
494 # Some properties for cycles
495 material_new.use_nodes = True
496 mat_P_BSDF = material_new.node_tree.nodes['Principled BSDF']
497 mat_P_BSDF.inputs['Metallic'].default_value = 0.5
498 mat_P_BSDF.inputs['Roughness'].default_value = 0.2
499 mat_P_BSDF.inputs['Transmission'].default_value = 0.5
500 mat_P_BSDF.inputs['IOR'].default_value = 0.8
502 # Always, when the material is changed, a new name is created. Note that
503 # this makes sense: Imagine, an other object uses the same material as the
504 # selected one. After changing the material of the selected object the old
505 # material should certainly not change and remain the same.
506 if material_type in {'1','2','3','4'}:
507 if "_repl" in material.name:
508 pos = material.name.rfind("_repl")
509 if material.name[pos+5:].isdigit():
510 counter = int(material.name[pos+5:])
511 material_new.name = material.name[:pos]+"_repl"+str(counter+1)
512 else:
513 material_new.name = material.name+"_repl1"
514 else:
515 material_new.name = material.name+"_repl1"
516 material_new.diffuse_color = material.diffuse_color
518 return material_new
521 # Get the collection of an object.
522 def get_collection_object(obj):
524 coll_all = obj.users_collection
525 if len(coll_all) > 0:
526 coll = coll_all[0]
527 else:
528 coll = bpy.context.scene.collection
530 return coll
533 # Draw an object (e.g. cube, sphere, cylinder, ...)
534 def draw_obj(atom_shape, atom, new_material):
536 # No change
537 if atom_shape == '0':
538 return None
540 if atom_shape == '1a': #Sphere mesh
541 bpy.ops.mesh.primitive_uv_sphere_add(
542 segments=32,
543 ring_count=32,
544 radius=1,
545 align='WORLD',
546 enter_editmode=False,
547 location=atom.location,
548 rotation=(0, 0, 0))
549 if atom_shape == '1b': #Sphere NURBS
550 bpy.ops.surface.primitive_nurbs_surface_sphere_add(
551 align='WORLD',
552 enter_editmode=False,
553 location=atom.location,
554 rotation=(0.0, 0.0, 0.0))
555 if atom_shape == '2': #Cube
556 bpy.ops.mesh.primitive_cube_add(
557 align='WORLD',
558 enter_editmode=False,
559 location=atom.location,
560 rotation=(0.0, 0.0, 0.0))
561 if atom_shape == '3': #Plane
562 bpy.ops.mesh.primitive_plane_add(
563 align='WORLD',
564 enter_editmode=False,
565 location=atom.location,
566 rotation=(0.0, 0.0, 0.0))
567 if atom_shape == '4a': #Circle
568 bpy.ops.mesh.primitive_circle_add(
569 vertices=32,
570 radius=1,
571 fill_type='NOTHING',
572 align='WORLD',
573 enter_editmode=False,
574 location=atom.location,
575 rotation=(0, 0, 0))
576 if atom_shape == '4b': #Circle NURBS
577 bpy.ops.surface.primitive_nurbs_surface_circle_add(
578 align='WORLD',
579 enter_editmode=False,
580 location=atom.location,
581 rotation=(0, 0, 0))
582 if atom_shape in {'5a','5b','5c','5d','5e'}: #Icosphere
583 index = {'5a':1,'5b':2,'5c':3,'5d':4,'5e':5}
584 bpy.ops.mesh.primitive_ico_sphere_add(
585 subdivisions=int(index[atom_shape]),
586 radius=1,
587 align='WORLD',
588 enter_editmode=False,
589 location=atom.location,
590 rotation=(0, 0, 0))
591 if atom_shape == '6a': #Cylinder
592 bpy.ops.mesh.primitive_cylinder_add(
593 vertices=32,
594 radius=1,
595 depth=2,
596 end_fill_type='NGON',
597 align='WORLD',
598 enter_editmode=False,
599 location=atom.location,
600 rotation=(0, 0, 0))
601 if atom_shape == '6b': #Cylinder NURBS
602 bpy.ops.surface.primitive_nurbs_surface_cylinder_add(
603 align='WORLD',
604 enter_editmode=False,
605 location=atom.location,
606 rotation=(0, 0, 0))
607 if atom_shape == '7': #Cone
608 bpy.ops.mesh.primitive_cone_add(
609 vertices=32,
610 radius1=1,
611 radius2=0,
612 depth=2,
613 end_fill_type='NGON',
614 align='WORLD',
615 enter_editmode=False,
616 location=atom.location,
617 rotation=(0, 0, 0))
618 if atom_shape == '8a': #Torus
619 bpy.ops.mesh.primitive_torus_add(
620 rotation=(0, 0, 0),
621 location=atom.location,
622 align='WORLD',
623 major_radius=1,
624 minor_radius=0.25,
625 major_segments=48,
626 minor_segments=12,
627 abso_major_rad=1,
628 abso_minor_rad=0.5)
629 if atom_shape == '8b': #Torus NURBS
630 bpy.ops.surface.primitive_nurbs_surface_torus_add(
631 align='WORLD',
632 enter_editmode=False,
633 location=atom.location,
634 rotation=(0, 0, 0))
636 new_atom = bpy.context.view_layer.objects.active
637 new_atom.scale = atom.scale + Vector((0.0,0.0,0.0))
638 new_atom.name = atom.name
639 new_atom.select_set(True)
641 new_atom.active_material = new_material
643 # If it is the representative object of a duplivert structure then
644 # transfer the parent and hide the new object.
645 if atom.parent != None:
646 new_atom.parent = atom.parent
647 new_atom.hide_set(True)
649 # Note the collection where the old object was placed into.
650 coll_old_atom = get_collection_object(atom)
652 # Note the collection where the new object was placed into.
653 coll_new_atom_past = get_collection_object(new_atom)
655 # If it is not the same collection then ...
656 if coll_new_atom_past != coll_old_atom:
657 # Put the new object into the collection of the old object and ...
658 coll_old_atom.objects.link(new_atom)
659 # ... unlink the new atom from its original collection.
660 coll_new_atom_past.objects.unlink(new_atom)
662 # If necessary, remove the childrens of the old object.
663 for child in atom.children:
664 bpy.ops.object.select_all(action='DESELECT')
665 child.hide_set(True)
666 child.select_set(True)
667 child.parent = None
668 coll_child = get_collection_object(child)
669 coll_child.objects.unlink(child)
670 bpy.ops.object.delete()
671 del(child)
673 # Deselect everything
674 bpy.ops.object.select_all(action='DESELECT')
675 # Make the old atom visible.
676 atom.hide_set(True)
677 # Select the old atom.
678 atom.select_set(True)
679 # Remove the parent if necessary.
680 atom.parent = None
681 # Unlink the old object from the collection.
682 coll_old_atom.objects.unlink(atom)
683 # Delete the old atom
684 bpy.ops.object.delete()
685 del(atom)
687 #if "_F2+_center" or "_F+_center" or "_F0_center" in coll_old_atom:
688 # print("Delete the collection")
690 return new_atom
693 # Draw a special object (e.g. halo, etc. ...)
694 def draw_obj_special(atom_shape, atom):
696 # Note the collection where 'atom' is placed into.
697 coll_atom = get_collection_object(atom)
699 # Now, create a collection for the new objects
700 coll_new = atom.name
701 # Create the new collection and ...
702 coll_new = bpy.data.collections.new(coll_new)
703 # ... link it to the collection, which contains 'atom'.
704 coll_atom.children.link(coll_new)
707 # F2+ center
708 if atom_shape == '1':
709 # Create first a cube
710 bpy.ops.mesh.primitive_cube_add(align='WORLD',
711 enter_editmode=False,
712 location=atom.location,
713 rotation=(0.0, 0.0, 0.0))
714 cube = bpy.context.view_layer.objects.active
715 cube.scale = atom.scale + Vector((0.0,0.0,0.0))
716 cube.name = atom.name + "_F2+_vac"
717 cube.select_set(True)
718 # New material for this cube
719 material_cube = bpy.data.materials.new(atom.name + "_F2+_vac")
720 material_cube.diffuse_color = [0.8, 0.0, 0.0, 1.0]
721 material_cube.metallic = 0.8
722 material_cube.specular_intensity = 0.5
723 material_cube.roughness = 0.3
724 material_cube.blend_method = 'OPAQUE'
725 material_cube.show_transparent_back = True
726 # Some properties for cycles
727 material_cube.use_nodes = True
728 mat_P_BSDF = material_cube.node_tree.nodes['Principled BSDF']
729 mat_P_BSDF.inputs['Metallic'].default_value = 0.1
730 mat_P_BSDF.inputs['Roughness'].default_value = 0.2
731 mat_P_BSDF.inputs['Transmission'].default_value = 0.9
732 mat_P_BSDF.inputs['IOR'].default_value = 0.8
733 cube.active_material = material_cube
734 # Put a nice point lamp inside the defect
735 lamp_data = bpy.data.lights.new(name=atom.name + "_F2+_lamp",
736 type="POINT")
737 lamp_data.distance = atom.scale[0] * 2.0
738 lamp_data.energy = 1.0
739 lamp_data.color = (0.8, 0.8, 0.8)
740 lamp = bpy.data.objects.new(atom.name + "_F2+_lamp", lamp_data)
741 lamp.location = Vector((0.0, 0.0, 0.0))
742 bpy.context.collection.objects.link(lamp)
743 lamp.parent = cube
744 # Some properties for cycles
745 lamp.data.use_nodes = True
746 lmp_P_BSDF = lamp.data.node_tree.nodes['Emission']
747 lmp_P_BSDF.inputs['Strength'].default_value = 2000
748 # The new 'atom' is the F2+ defect
749 new_atom = cube
751 # Note the collection where all the new objects were placed into.
752 # We use only one object, the cube
753 coll_ori = get_collection_object(cube)
755 # If it is not the same collection then ...
756 if coll_ori != coll_new:
757 # Put all new objects into the new collection and ...
758 coll_new.objects.link(cube)
759 coll_new.objects.link(lamp)
760 # ... unlink them from their original collection.
761 coll_ori.objects.unlink(cube)
762 coll_ori.objects.unlink(lamp)
764 coll_new.name = atom.name + "_F2+_center"
766 if atom.parent != None:
767 cube.parent = atom.parent
768 cube.hide_set(True)
769 lamp.hide_set(True)
771 # F+ center
772 if atom_shape == '2':
773 # Create first a cube
774 bpy.ops.mesh.primitive_cube_add(align='WORLD',
775 enter_editmode=False,
776 location=atom.location,
777 rotation=(0.0, 0.0, 0.0))
778 cube = bpy.context.view_layer.objects.active
779 cube.scale = atom.scale + Vector((0.0,0.0,0.0))
780 cube.name = atom.name + "_F+_vac"
781 cube.select_set(True)
782 # New material for this cube
783 material_cube = bpy.data.materials.new(atom.name + "_F+_vac")
784 material_cube.diffuse_color = [0.0, 0.0, 0.8, 1.0]
785 material_cube.metallic = 0.8
786 material_cube.specular_intensity = 0.5
787 material_cube.roughness = 0.3
788 material_cube.blend_method = 'OPAQUE'
789 material_cube.show_transparent_back = True
790 # Some properties for cycles
791 material_cube.use_nodes = True
792 mat_P_BSDF = material_cube.node_tree.nodes['Principled BSDF']
793 mat_P_BSDF.inputs['Metallic'].default_value = 0.1
794 mat_P_BSDF.inputs['Roughness'].default_value = 0.2
795 mat_P_BSDF.inputs['Transmission'].default_value = 0.9
796 mat_P_BSDF.inputs['IOR'].default_value = 0.8
797 cube.active_material = material_cube
798 # Create now an electron
799 scale = atom.scale / 10.0
800 bpy.ops.surface.primitive_nurbs_surface_sphere_add(
801 align='WORLD',
802 enter_editmode=False,
803 location=(0.0, 0.0, 0.0),
804 rotation=(0.0, 0.0, 0.0))
805 electron = bpy.context.view_layer.objects.active
806 electron.scale = scale
807 electron.name = atom.name + "_F+_electron"
808 electron.parent = cube
809 # New material for the electron
810 material_electron = bpy.data.materials.new(atom.name + "_F+-center")
811 material_electron.diffuse_color = [0.0, 0.0, 0.8, 1.0]
812 material_electron.metallic = 0.8
813 material_electron.specular_intensity = 0.5
814 material_electron.roughness = 0.3
815 material_electron.blend_method = 'OPAQUE'
816 material_electron.show_transparent_back = False
817 electron.active_material = material_electron
818 # Put a nice point lamp inside the electron
819 lamp_data = bpy.data.lights.new(name=atom.name + "_F+_lamp",
820 type="POINT")
821 lamp_data.distance = atom.scale[0] * 2.0
822 lamp_data.energy = 1.0
823 lamp_data.color = (0.8, 0.8, 0.8)
824 lamp = bpy.data.objects.new(atom.name + "_F+_lamp", lamp_data)
825 lamp.location = Vector((scale[0]*1.5, 0.0, 0.0))
826 bpy.context.collection.objects.link(lamp)
827 lamp.parent = cube
828 # Some properties for cycles
829 lamp.data.use_nodes = True
830 lmp_P_BSDF = lamp.data.node_tree.nodes['Emission']
831 lmp_P_BSDF.inputs['Strength'].default_value = 2000
832 # The new 'atom' is the F+ defect complex + lamp
833 new_atom = cube
835 # Note the collection where all the new objects were placed into.
836 # We use only one object, the cube
837 coll_ori = get_collection_object(cube)
839 # If it is not the same collection then ...
840 if coll_ori != coll_new:
841 # Put all new objects into the new collection and ...
842 coll_new.objects.link(cube)
843 coll_new.objects.link(electron)
844 coll_new.objects.link(lamp)
845 # ... unlink them from their original collection.
846 coll_ori.objects.unlink(cube)
847 coll_ori.objects.unlink(electron)
848 coll_ori.objects.unlink(lamp)
850 coll_new.name = atom.name + "_F+_center"
852 if atom.parent != None:
853 cube.parent = atom.parent
854 cube.hide_set(True)
855 electron.hide_set(True)
856 lamp.hide_set(True)
858 # F0 center
859 if atom_shape == '3':
860 # Create first a cube
861 bpy.ops.mesh.primitive_cube_add(align='WORLD',
862 enter_editmode=False,
863 location=atom.location,
864 rotation=(0.0, 0.0, 0.0))
865 cube = bpy.context.view_layer.objects.active
866 cube.scale = atom.scale + Vector((0.0,0.0,0.0))
867 cube.name = atom.name + "_F0_vac"
868 cube.select_set(True)
869 # New material for this cube
870 material_cube = bpy.data.materials.new(atom.name + "_F0_vac")
871 material_cube.diffuse_color = [0.8, 0.8, 0.8, 1.0]
872 material_cube.metallic = 0.8
873 material_cube.specular_intensity = 0.5
874 material_cube.roughness = 0.83
875 material_cube.blend_method = 'OPAQUE'
876 material_cube.show_transparent_back = True
877 # Some properties for cycles
878 material_cube.use_nodes = True
879 mat_P_BSDF = material_cube.node_tree.nodes['Principled BSDF']
880 mat_P_BSDF.inputs['Metallic'].default_value = 0.1
881 mat_P_BSDF.inputs['Roughness'].default_value = 0.2
882 mat_P_BSDF.inputs['Transmission'].default_value = 0.9
883 mat_P_BSDF.inputs['IOR'].default_value = 0.8
884 cube.active_material = material_cube
885 # Create now two electrons
886 scale = atom.scale / 10.0
887 bpy.ops.surface.primitive_nurbs_surface_sphere_add(
888 align='WORLD',
889 enter_editmode=False,
890 location=(scale[0]*1.5,0.0,0.0),
891 rotation=(0.0, 0.0, 0.0))
892 electron1 = bpy.context.view_layer.objects.active
893 electron1.scale = scale
894 electron1.name = atom.name + "_F0_electron1"
895 electron1.parent = cube
896 bpy.ops.surface.primitive_nurbs_surface_sphere_add(
897 align='WORLD',
898 enter_editmode=False,
899 location=(-scale[0]*1.5,0.0,0.0),
900 rotation=(0.0, 0.0, 0.0))
901 electron2 = bpy.context.view_layer.objects.active
902 electron2.scale = scale
903 electron2.name = atom.name + "_F0_electron2"
904 electron2.parent = cube
905 # New material for the electrons
906 material_electron = bpy.data.materials.new(atom.name + "_F0-center")
907 material_electron.diffuse_color = [0.0, 0.0, 0.8, 1.0]
908 material_electron.metallic = 0.8
909 material_electron.specular_intensity = 0.5
910 material_electron.roughness = 0.3
911 material_electron.blend_method = 'OPAQUE'
912 material_electron.show_transparent_back = False
913 electron1.active_material = material_electron
914 electron2.active_material = material_electron
915 # Put two nice point lamps inside the electrons
916 lamp1_data = bpy.data.lights.new(name=atom.name + "_F0_lamp1",
917 type="POINT")
918 lamp1_data.distance = atom.scale[0] * 2.0
919 lamp1_data.energy = 1.0
920 lamp1_data.color = (0.8, 0.8, 0.8)
921 lamp1 = bpy.data.objects.new(atom.name + "_F0_lamp", lamp1_data)
922 lamp1.location = Vector((scale[0]*1.5, 0.0, 0.0))
923 bpy.context.collection.objects.link(lamp1)
924 lamp1.parent = cube
925 lamp2_data = bpy.data.lights.new(name=atom.name + "_F0_lamp2",
926 type="POINT")
927 lamp2_data.distance = atom.scale[0] * 2.0
928 lamp2_data.energy = 1.0
929 lamp2_data.color = (0.8, 0.8, 0.8)
930 lamp2 = bpy.data.objects.new(atom.name + "_F0_lamp", lamp2_data)
931 lamp2.location = Vector((-scale[0]*1.5, 0.0, 0.0))
932 bpy.context.collection.objects.link(lamp2)
933 lamp2.parent = cube
934 # Some properties for cycles
935 lamp1.data.use_nodes = True
936 lamp2.data.use_nodes = True
937 lmp1_P_BSDF = lamp1.data.node_tree.nodes['Emission']
938 lmp2_P_BSDF = lamp1.data.node_tree.nodes['Emission']
939 lmp1_P_BSDF.inputs['Strength'].default_value = 200
940 lmp2_P_BSDF.inputs['Strength'].default_value = 200
941 # The new 'atom' is the F0 defect complex + lamps
942 new_atom = cube
944 # Note the collection where all the new objects were placed into.
945 # We use only one object, the cube
946 coll_ori = get_collection_object(cube)
948 # If it is not the same collection then ...
949 if coll_ori != coll_new:
950 # Put all new objects into the collection of 'atom' and ...
951 coll_new.objects.link(cube)
952 coll_new.objects.link(electron1)
953 coll_new.objects.link(electron2)
954 coll_new.objects.link(lamp1)
955 coll_new.objects.link(lamp2)
956 # ... unlink them from their original collection.
957 coll_ori.objects.unlink(cube)
958 coll_ori.objects.unlink(electron1)
959 coll_ori.objects.unlink(electron2)
960 coll_ori.objects.unlink(lamp1)
961 coll_ori.objects.unlink(lamp2)
963 coll_new.name = atom.name + "_F0_center"
965 if atom.parent != None:
966 cube.parent = atom.parent
967 cube.hide_set(True)
968 electron1.hide_set(True)
969 electron2.hide_set(True)
970 lamp1.hide_set(True)
971 lamp2.hide_set(True)
973 # Deselect everything
974 bpy.ops.object.select_all(action='DESELECT')
975 # Make the old atom visible.
976 atom.hide_set(True)
977 # Select the old atom.
978 atom.select_set(True)
979 # Remove the parent if necessary.
980 atom.parent = None
981 # Unlink the old object from the collection.
982 coll_atom.objects.unlink(atom)
983 # Delete the old atom
984 bpy.ops.object.delete()
985 del(atom)
987 return new_atom
990 # Initialization of the list 'ELEMENTS'.
991 def read_elements():
993 del ELEMENTS[:]
995 for item in ELEMENTS_DEFAULT:
997 # All three radii into a list
998 radii = [item[4],item[5],item[6]]
999 # The handling of the ionic radii will be done later. So far, it is an
1000 # empty list.
1001 radii_ionic = item[7:]
1003 li = ElementProp(item[0],item[1],item[2],item[3],
1004 radii,radii_ionic)
1005 ELEMENTS.append(li)
1008 # Custom data file: changing color and radii by using the list 'ELEMENTS'.
1009 def custom_datafile_change_atom_props():
1011 for atom in bpy.context.selected_objects:
1012 if len(atom.children) != 0:
1013 child = atom.children[0]
1014 if child.type in {'SURFACE', 'MESH', 'META'}:
1015 for element in ELEMENTS:
1016 if element.name in atom.name:
1017 child.scale = (element.radii[0],) * 3
1018 child.active_material.diffuse_color = element.color
1019 else:
1020 if atom.type in {'SURFACE', 'MESH', 'META'}:
1021 for element in ELEMENTS:
1022 if element.name in atom.name:
1023 atom.scale = (element.radii[0],) * 3
1024 atom.active_material.diffuse_color = element.color
1027 # Reading a custom data file and modifying the list 'ELEMENTS'.
1028 def custom_datafile(path_datafile):
1030 if path_datafile == "":
1031 return False
1033 path_datafile = bpy.path.abspath(path_datafile)
1035 if os.path.isfile(path_datafile) == False:
1036 return False
1038 # The whole list gets deleted! We build it new.
1039 del ELEMENTS[:]
1041 # Read the data file, which contains all data
1042 # (atom name, radii, colors, etc.)
1043 data_file_p = open(path_datafile, "r")
1045 for line in data_file_p:
1047 if "Atom" in line:
1049 line = data_file_p.readline()
1050 # Number
1051 line = data_file_p.readline()
1052 number = line[19:-1]
1053 # Name
1054 line = data_file_p.readline()
1055 name = line[19:-1]
1056 # Short name
1057 line = data_file_p.readline()
1058 short_name = line[19:-1]
1059 # Color
1060 line = data_file_p.readline()
1061 color_value = line[19:-1].split(',')
1062 color = [float(color_value[0]),
1063 float(color_value[1]),
1064 float(color_value[2]),
1065 float(color_value[3])]
1066 # Used radius
1067 line = data_file_p.readline()
1068 radius_used = float(line[19:-1])
1069 # Atomic radius
1070 line = data_file_p.readline()
1071 radius_atomic = float(line[19:-1])
1072 # Van der Waals radius
1073 line = data_file_p.readline()
1074 radius_vdW = float(line[19:-1])
1075 radii = [radius_used,radius_atomic,radius_vdW]
1076 radii_ionic = []
1078 element = ElementProp(number,name,short_name,color,
1079 radii, radii_ionic)
1081 ELEMENTS.append(element)
1083 data_file_p.close()
1085 return True