Newer
Older
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
#
# Main author : Clemens Barth (Blendphys@root-1.de)
#
# Homepage(Wiki) : http://development.root-1.de/Atomic_Blender.php
#
# Start of project : 2012-03-25 by Clemens Barth
#
#
#
# To do:
# ======
#
# 1. Include other shapes: dodecahedron, ...
# 2. Skin option for parabolic shaped clusters
# 3. Skin option for icosahedron
CoDEmanX
committed
# 4. Icosahedron: unlimited size ...
#
bl_info = {
"name": "Atomic Blender - Cluster",
"description": "Creating cluster formed by atoms",
"author": "Clemens Barth",
"location": "Panel: View 3D - Tools (left side)",
"warning": "",
CoDEmanX
committed
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
"Scripts/Add_Mesh/Cluster",
"tracker_url": "https://developer.blender.org/T31618",
"category": "Add Mesh"}
import os
import io
import bpy
from bpy.types import Operator, Panel
from bpy_extras.io_utils import ImportHelper, ExportHelper
from bpy.props import (StringProperty,
BoolProperty,
EnumProperty,
IntProperty,
FloatProperty)
from . import add_mesh_cluster
# -----------------------------------------------------------------------------
# GUI
class CLASS_ImportCluster(bpy.types.Operator):
bl_idname = "mesh.cluster"
bl_label = "Atom cluster"
def execute(self, context):
global ATOM_Cluster_PANEL
ATOM_Cluster_PANEL = 1
return {'FINISHED'}
class CLASS_atom_cluster_panel(Panel):
bl_label = "Atomic Blender - Cluster"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOL_PROPS"
CoDEmanX
committed
CoDEmanX
committed
def draw(self, context):
layout = self.layout
CoDEmanX
committed
row = layout.row()
row.label(text="Cluster properties")
box = layout.box()
row = box.row()
row.prop(scn, "shape")
if scn.shape in ["parabolid_square","parabolid_ab","parabolid_abc"]:
row = box.row()
row.prop(scn, "parabol_diameter")
row = box.row()
row.prop(scn, "parabol_height")
elif scn.shape in ["icosahedron"]:
row = box.row()
row.prop(scn, "icosahedron_size")
else:
row = box.row()
row.prop(scn, "size")
row = box.row()
row.prop(scn, "skin")
row = box.row()
row.prop(scn, "lattice_parameter")
row = box.row()
row.prop(scn, "element")
row = box.row()
CoDEmanX
committed
row.prop(scn, "radius_type")
row = box.row()
row.prop(scn, "scale_radius")
row = box.row()
row.prop(scn, "scale_distances")
CoDEmanX
committed
row = layout.row()
row.label(text="Load cluster")
box = layout.box()
CoDEmanX
committed
row = box.row()
row.operator("atom_cluster.load")
row = box.row()
row.label(text="Number of atoms")
row = box.row()
CoDEmanX
committed
row.prop(scn, "atom_number_total")
CoDEmanX
committed
row.prop(scn, "atom_number_drawn")
row = layout.row()
row.label(text="Modify cluster")
box = layout.box()
row = box.row()
row.label(text="All changes concern:")
row = box.row()
row.prop(scn, "radius_how")
row = box.row()
row.label(text="1. Change type of radii")
row = box.row()
row.prop(scn, "radius_type")
row = box.row()
row.label(text="2. Change atom radii by scale")
row = box.row()
col = row.column()
CoDEmanX
committed
col.prop(scn, "radius_all")
col = row.column(align=True)
col.operator( "atom_cluster.radius_all_bigger" )
col.operator( "atom_cluster.radius_all_smaller" )
# The properties (gadgets) in the panel. They all go to scene
CoDEmanX
committed
# during initialization (see end)
class CLASS_atom_cluster_Properties(bpy.types.PropertyGroup):
def Callback_radius_type(self, context):
DEF_atom_cluster_radius_type(scn.radius_type,
scn.radius_how,)
size = FloatProperty(
name = "Size", default=30.0, min=0.1,
description = "Size of cluster in Angstroem")
skin = FloatProperty(
name = "Skin", default=1.0, min=0.0, max = 1.0,
description = "Skin of cluster in % of size (skin=1.0: show all atoms, skin=0.1: show only the outer atoms)")
parabol_diameter = FloatProperty(
name = "Diameter", default=30.0, min=0.1,
description = "Top diameter in Angstroem")
parabol_height = FloatProperty(
CoDEmanX
committed
name = "Height", default=30.0, min=0.1,
description = "Height in Angstroem")
CoDEmanX
committed
name = "Size", default=1, min=1, max=13,
description = "Size n: 1 (13 atoms), 2 (55 atoms), 3 (147 atoms), 4 (309 atoms), 5 (561 atoms), ..., 13 (8217 atoms)")
shape = EnumProperty(
name="",
description="Choose the shape of the cluster",
items=(('sphere_square', "Sphere - square", "Sphere with square lattice"),
('sphere_hex_ab', "Sphere - hex ab", "Sphere with hexagonal ab-lattice"),
('sphere_hex_abc', "Sphere - hex abc", "Sphere with hexagonal abc-lattice"),
('pyramide_square', "Pyramide - Square", "Pyramide: square (abc-lattice)"),
('pyramide_hex_abc', "Pyramide - Tetraeder", "Pyramide: tetraeder (abcabc-lattice)"),
('octahedron', "Octahedron", "Octahedron"),
('truncated_octahedron', "Truncated octahedron", "Truncated octahedron"),
('parabolid_square', "Paraboloid: square", "Paraboloid with square lattice"),
('parabolid_ab', "Paraboloid: hex ab", "Paraboloid with ab-lattice"),
('parabolid_abc', "Paraboloid: hex abc", "Paraboloid with abc-lattice")),
CoDEmanX
committed
default='sphere_square',)
lattice_parameter = FloatProperty(
description = "Lattice parameter in Angstroem")
element = StringProperty(name="Element",
default="Gold", description = "Enter the name of the element")
radius_type = EnumProperty(
name="Radius",
description="Which type of atom radii?",
items=(('0',"predefined", "Use pre-defined radii"),
('1',"atomic", "Use atomic radii"),
('2',"van der Waals","Use van der Waals radii")),
default='0',)
scale_radius = FloatProperty(
name = "Scale R", default=1.0, min=0.0,
description = "Scale radius of atoms")
scale_distances = FloatProperty(
name = "Scale d", default=1.0, min=0.0,
description = "Scale distances")
CoDEmanX
committed
atom_number_total = StringProperty(name="Total",
CoDEmanX
committed
default="---", description = "Number of all atoms in the cluster")
atom_number_drawn = StringProperty(name="Drawn",
CoDEmanX
committed
default="---", description = "Number of drawn atoms in the cluster")
radius_how = EnumProperty(
name="",
description="Which objects shall be modified?",
items=(('ALL_ACTIVE',"all active objects", "in the current layer"),
('ALL_IN_LAYER',"all"," in active layer(s)")),
default='ALL_ACTIVE',)
radius_type = EnumProperty(
name="Type",
description="Which type of atom radii?",
items=(('0',"predefined", "Use pre-defined radii"),
('1',"atomic", "Use atomic radii"),
('2',"van der Waals","Use van der Waals radii")),
default='0',update=Callback_radius_type)
radius_all = FloatProperty(
name="Scale", default = 1.05, min=0.0,
description="Put in the scale factor")
CoDEmanX
committed
# The button for reloading the atoms and creating the scene
class CLASS_atom_cluster_load_button(Operator):
bl_idname = "atom_cluster.load"
bl_label = "Load"
bl_description = "Load the cluster"
def execute(self, context):
add_mesh_cluster.DEF_atom_read_atom_data()
del add_mesh_cluster.ATOM_CLUSTER_ALL_ATOMS[:]
if scn.shape in ["parabolid_ab", "parabolid_abc", "parabolid_square"]:
parameter1 = scn.parabol_height
parameter2 = scn.parabol_diameter
elif scn.shape == "pyramide_hex_abc":
parameter1 = scn.size * 1.6
parameter2 = scn.skin
elif scn.shape == "pyramide_square":
parameter1 = scn.size * 1.4
parameter2 = scn.skin
elif scn.shape in ["octahedron", "truncated_octahedron"]:
parameter1 = scn.size * 1.4
parameter2 = scn.skin
CoDEmanX
committed
parameter1 = scn.icosahedron_size
else:
parameter1 = scn.size
parameter2 = scn.skin
if scn.shape in ["octahedron", "truncated_octahedron", "sphere_square", "pyramide_square", "parabolid_square"]:
numbers = add_mesh_cluster.create_square_lattice(
CoDEmanX
committed
scn.shape,
parameter1,
parameter2,
(scn.lattice_parameter/2.0))
if scn.shape in ["sphere_hex_ab", "parabolid_ab"]:
numbers = add_mesh_cluster.create_hexagonal_abab_lattice(
CoDEmanX
committed
scn.shape,
CoDEmanX
committed
parameter2,
scn.lattice_parameter)
if scn.shape in ["sphere_hex_abc", "pyramide_hex_abc", "parabolid_abc"]:
numbers = add_mesh_cluster.create_hexagonal_abcabc_lattice(
CoDEmanX
committed
scn.shape,
CoDEmanX
committed
parameter2,
scn.lattice_parameter)
CoDEmanX
committed
CoDEmanX
committed
numbers = add_mesh_cluster.create_icosahedron(
parameter1,
DEF_atom_draw_atoms(scn.element,
scn.radius_type,
scn.scale_radius,
CoDEmanX
committed
scn.scale_distances)
scn.atom_number_total = str(numbers[0])
scn.atom_number_drawn = str(numbers[1])
CoDEmanX
committed
CoDEmanX
committed
def DEF_atom_draw_atoms(prop_element,
prop_radius_type,
prop_scale_radius,
prop_scale_distances):
current_layers=bpy.context.scene.layers
CoDEmanX
committed
for element in add_mesh_cluster.ATOM_CLUSTER_ELEMENTS:
if prop_element in element.name:
number = element.number
name = element.name
color = element.color
radii = element.radii
CoDEmanX
committed
break
material = bpy.data.materials.new(name)
material.name = name
material.diffuse_color = color
atom_vertices = []
for atom in add_mesh_cluster.ATOM_CLUSTER_ALL_ATOMS:
atom_vertices.append( atom.location * prop_scale_distances )
CoDEmanX
committed
# Build the mesh
atom_mesh = bpy.data.meshes.new("Mesh_"+name)
atom_mesh.from_pydata(atom_vertices, [], [])
atom_mesh.update()
new_atom_mesh = bpy.data.objects.new(name, atom_mesh)
bpy.context.scene.objects.link(new_atom_mesh)
CoDEmanX
committed
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
bpy.ops.surface.primitive_nurbs_surface_sphere_add(
view_align=False, enter_editmode=False,
location=(0,0,0), rotation=(0.0, 0.0, 0.0),
layers=current_layers)
ball = bpy.context.scene.objects.active
ball.scale = (radii[int(prop_radius_type)]*prop_scale_radius,) * 3
ball.active_material = material
ball.parent = new_atom_mesh
new_atom_mesh.dupli_type = 'VERTS'
# ------------------------------------------------------------------------
# SELECT ALL LOADED OBJECTS
bpy.ops.object.select_all(action='DESELECT')
new_atom_mesh.select = True
bpy.context.scene.objects.active = new_atom_mesh
return True
# Routine to modify the radii via the type: predefined, atomic or van der Waals
# Explanations here are also valid for the next 3 DEFs.
def DEF_atom_cluster_radius_type(rtype,how):
if how == "ALL_IN_LAYER":
# Note all layers that are active.
layers = []
for i in range(20):
if bpy.context.scene.layers[i] == True:
layers.append(i)
# Put all objects, which are in the layers, into a list.
change_objects = []
for obj in bpy.context.scene.objects:
for layer in layers:
if obj.layers[layer] == True:
change_objects.append(obj)
# Consider all objects, which are in the list 'change_objects'.
for obj in change_objects:
if len(obj.children) != 0:
if obj.children[0].type == "SURFACE" or obj.children[0].type == "MESH":
for element in add_mesh_cluster.ATOM_CLUSTER_ELEMENTS:
if element.name in obj.name:
obj.children[0].scale = (element.radii[int(rtype)],) * 3
else:
if obj.type == "SURFACE" or obj.type == "MESH":
for element in add_mesh_cluster.ATOM_CLUSTER_ELEMENTS:
if element.name in obj.name:
obj.scale = (element.radii[int(rtype)],) * 3
CoDEmanX
committed
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
# Routine to scale the radii of all atoms
def DEF_atom_cluster_radius_all(scale, how):
if how == "ALL_IN_LAYER":
layers = []
for i in range(20):
if bpy.context.scene.layers[i] == True:
layers.append(i)
change_objects = []
for obj in bpy.context.scene.objects:
for layer in layers:
if obj.layers[layer] == True:
change_objects.append(obj)
for obj in change_objects:
if len(obj.children) != 0:
if obj.children[0].type == "SURFACE" or obj.children[0].type == "MESH":
if "Stick" not in obj.name:
obj.children[0].scale *= scale
else:
if obj.type == "SURFACE" or obj.type == "MESH":
if "Stick" not in obj.name:
obj.scale *= scale
if how == "ALL_ACTIVE":
for obj in bpy.context.selected_objects:
if len(obj.children) != 0:
if obj.children[0].type == "SURFACE" or obj.children[0].type == "MESH":
if "Stick" not in obj.name:
obj.children[0].scale *= scale
else:
if obj.type == "SURFACE" or obj.type == "MESH":
if "Stick" not in obj.name:
obj.scale *= scale
# Button for increasing the radii of all atoms
class CLASS_atom_cluster_radius_all_bigger_button(Operator):
bl_idname = "atom_cluster.radius_all_bigger"
bl_label = "Bigger ..."
bl_description = "Increase the radii of the atoms"
def execute(self, context):
DEF_atom_cluster_radius_all(
scn.radius_all,
scn.radius_how,)
return {'FINISHED'}
# Button for decreasing the radii of all atoms
class CLASS_atom_cluster_radius_all_smaller_button(Operator):
bl_idname = "atom_cluster.radius_all_smaller"
bl_label = "Smaller ..."
bl_description = "Decrease the radii of the atoms"
def execute(self, context):
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
DEF_atom_cluster_radius_all(
1.0/scn.radius_all,
scn.radius_how,)
return {'FINISHED'}
# Routine to scale the radii of all atoms
def DEF_atom_cluster_radius_all(scale, how):
if how == "ALL_IN_LAYER":
layers = []
for i in range(20):
if bpy.context.scene.layers[i] == True:
layers.append(i)
change_objects = []
for obj in bpy.context.scene.objects:
for layer in layers:
if obj.layers[layer] == True:
change_objects.append(obj)
for obj in change_objects:
if len(obj.children) != 0:
if obj.children[0].type == "SURFACE" or obj.children[0].type == "MESH":
if "Stick" not in obj.name:
obj.children[0].scale *= scale
else:
if obj.type == "SURFACE" or obj.type == "MESH":
if "Stick" not in obj.name:
obj.scale *= scale
if how == "ALL_ACTIVE":
for obj in bpy.context.selected_objects:
if len(obj.children) != 0:
if obj.children[0].type == "SURFACE" or obj.children[0].type == "MESH":
if "Stick" not in obj.name:
obj.children[0].scale *= scale
else:
if obj.type == "SURFACE" or obj.type == "MESH":
if "Stick" not in obj.name:
obj.scale *= scale
# The entry into the menu 'file -> import'
def DEF_menu_func(self, context):
self.layout.operator(CLASS_ImportCluster.bl_idname, icon='PLUGIN')
def register():
bpy.utils.register_module(__name__)
CoDEmanX
committed
CLASS_atom_cluster_Properties)
CoDEmanX
committed
def unregister():
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()