diff options
author | Campbell Barton <ideasman42@gmail.com> | 2011-12-02 03:22:11 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2011-12-02 03:22:11 +0400 |
commit | 47d6495586f6e1e2b9140820af9d87f4d5706702 (patch) | |
tree | 8f06def0c14bd046f383abc46c2570b1ec31d1a6 /io_mesh_pdb | |
parent | 09a798bb6b371bc3f7fb3228b285bfbb8a867dda (diff) |
general cleanup, also added some TODO comments
Diffstat (limited to 'io_mesh_pdb')
-rw-r--r-- | io_mesh_pdb/__init__.py | 371 | ||||
-rw-r--r-- | io_mesh_pdb/import_pdb.py | 520 |
2 files changed, 425 insertions, 466 deletions
diff --git a/io_mesh_pdb/__init__.py b/io_mesh_pdb/__init__.py index 69046b84..4868ac25 100644 --- a/io_mesh_pdb/__init__.py +++ b/io_mesh_pdb/__init__.py @@ -33,6 +33,7 @@ bl_info = { import bpy +from bpy.types import Operator, Panel from bpy_extras.io_utils import ImportHelper from bpy.props import (StringProperty, BoolProperty, @@ -49,7 +50,7 @@ from . import import_pdb # The panel, which is loaded after the file has been # chosen via the menu 'File -> Import' -class CLASS_atom_pdb_panel(bpy.types.Panel): +class CLASS_atom_pdb_panel(Panel): bl_label = "PDB - Atomic Blender" #bl_space_type = "PROPERTIES" #bl_region_type = "WINDOW" @@ -62,18 +63,18 @@ class CLASS_atom_pdb_panel(bpy.types.Panel): # I explain it in the following from my point of view: # # Before this class is entirely treaten (here: drawing the panel) the - # poll method is called first. Basically, some conditions are - # checked before other things in the class are done afterwards. If a - # condition is not valid, one returns 'False' such that nothing further + # poll method is called first. Basically, some conditions are + # checked before other things in the class are done afterwards. If a + # condition is not valid, one returns 'False' such that nothing further # is done. 'True' means: 'Go on' # # In the case here, it is verified if the ATOM_PDB_FILEPATH variable contains # a name. If not - and this is the case directly after having started the # script - the panel does not appear because 'False' is returned. However, - # as soon as a file has been chosen, the panel appears because + # as soon as a file has been chosen, the panel appears because # ATOM_PDB_FILEPATH contains a name. # - # Please, correct me if I'm wrong. + # Please, correct me if I'm wrong. @classmethod def poll(self, context): if import_pdb.ATOM_PDB_FILEPATH == "": @@ -96,288 +97,285 @@ class CLASS_atom_pdb_panel(bpy.types.Panel): col.prop(scn, "atom_pdb_PDB_file") layout.separator() - - row = layout.row() - col = row.column(align=True) + + row = layout.row() + col = row.column(align=True) col.prop(scn, "use_atom_pdb_mesh") col.prop(scn, "atom_pdb_mesh_azimuth") - col.prop(scn, "atom_pdb_mesh_zenith") - - - col = row.column(align=True) + col.prop(scn, "atom_pdb_mesh_zenith") + + + col = row.column(align=True) col.label(text="Scaling factors") col.prop(scn, "atom_pdb_scale_ballradius") col.prop(scn, "atom_pdb_scale_distances") - row = layout.row() + row = layout.row() col = row.column() col.prop(scn, "use_atom_pdb_sticks") col = row.column(align=True) col.prop(scn, "atom_pdb_sticks_sectors") col.prop(scn, "atom_pdb_sticks_radius") - row = layout.row() - row.prop(scn, "use_atom_pdb_center") - - row = layout.row() + row = layout.row() + row.prop(scn, "use_atom_pdb_center") + + row = layout.row() col = row.column() col.prop(scn, "use_atom_pdb_cam") - col.prop(scn, "use_atom_pdb_lamp") - col = row.column() + col.prop(scn, "use_atom_pdb_lamp") + col = row.column() col.operator("atom_pdb.button_reload") # TODO, use lanel() instead col.prop(scn, "atom_pdb_number_atoms") layout.separator() - - row = layout.row() + + row = layout.row() row.operator("atom_pdb.button_distance") - row.prop(scn, "atom_pdb_distance") + row.prop(scn, "atom_pdb_distance") layout.separator() - + row = layout.row() row.label(text="All changes concern:") row = layout.row() - row.prop(scn, "atom_pdb_radius_how") - - row = layout.row() - row.label(text="1. Change type of radii") + row.prop(scn, "atom_pdb_radius_how") + + row = layout.row() + row.label(text="1. Change type of radii") + row = layout.row() + row.prop(scn, "atom_pdb_radius_type") + + row = layout.row() + row.label(text="2. Change atom radii in pm") + row = layout.row() + row.prop(scn, "atom_pdb_radius_pm_name") row = layout.row() - row.prop(scn, "atom_pdb_radius_type") - - row = layout.row() - row.label(text="2. Change atom radii in pm") - row = layout.row() - row.prop(scn, "atom_pdb_radius_pm_name") - row = layout.row() row.prop(scn, "atom_pdb_radius_pm") - - row = layout.row() - row.label(text="3. Change atom radii by scale") + row = layout.row() - col = row.column() + row.label(text="3. Change atom radii by scale") + row = layout.row() + col = row.column() col.prop(scn, "atom_pdb_radius_all") - col = row.column(align=True) + col = row.column(align=True) col.operator( "atom_pdb.radius_all_bigger" ) col.operator( "atom_pdb.radius_all_smaller" ) - + if bpy.context.mode == 'EDIT_MESH': - + layout.separator() row = layout.row() row.operator( "atom_pdb.separate_atom" ) class CLASS_atom_pdb_IO(bpy.types.PropertyGroup): - + def Callback_radius_type(self, context): scnn = bpy.context.scene import_pdb.DEF_atom_pdb_radius_type( scnn.atom_pdb_radius_type, scnn.atom_pdb_radius_how, ) - + def Callback_radius_pm(self, context): scnn = bpy.context.scene import_pdb.DEF_atom_pdb_radius_pm( - scnn.atom_pdb_radius_pm_name, + scnn.atom_pdb_radius_pm_name, scnn.atom_pdb_radius_pm, scnn.atom_pdb_radius_how, ) - + # In the file dialog window scn = bpy.types.Scene scn.use_atom_pdb_cam = BoolProperty( - name="Camera", default=False, - description="Do you need a camera?") + name="Camera", default=False, + description="Do you need a camera?") scn.use_atom_pdb_lamp = BoolProperty( - name="Lamp", default=False, - description = "Do you need a lamp?") + name="Lamp", default=False, + description = "Do you need a lamp?") scn.use_atom_pdb_mesh = BoolProperty( - name = "Mesh balls", default=False, - description = "Do you want to use mesh balls instead of NURBS?") + name = "Mesh balls", default=False, + description = "Do you want to use mesh balls instead of NURBS?") scn.atom_pdb_mesh_azimuth = IntProperty( - name = "Azimuth", default=32, min=0, + name = "Azimuth", default=32, min=0, description = "Number of sectors (azimuth)") scn.atom_pdb_mesh_zenith = IntProperty( - name = "Zenith", default=32, min=0, + name = "Zenith", default=32, min=0, description = "Number of sectors (zenith)") scn.atom_pdb_scale_ballradius = FloatProperty( - name = "Balls", default=1.0, min=0.0, + name = "Balls", default=1.0, min=0.0, description = "Scale factor for all atom radii") scn.atom_pdb_scale_distances = FloatProperty ( - name = "Distances", default=1.0, min=0.0, + name = "Distances", default=1.0, min=0.0, description = "Scale factor for all distances") scn.use_atom_pdb_center = BoolProperty( - name = "Object to origin", default=True, + name = "Object to origin", default=True, description = "Shall the object first put into the global origin " - "before applying the offsets on the left?") + "before applying the offsets on the left?") scn.use_atom_pdb_sticks = BoolProperty( - name="Use sticks", default=False, - description="Do you want to display also the sticks?") + name="Use sticks", default=False, + description="Do you want to display also the sticks?") scn.atom_pdb_sticks_sectors = IntProperty( name = "Sector", default=20, min=0, - description="Number of sectors of a stick") + description="Number of sectors of a stick") scn.atom_pdb_sticks_radius = FloatProperty( - name = "Radius", default=0.1, min=0.0, - description ="Radius of a stick") + name = "Radius", default=0.1, min=0.0, + description ="Radius of a stick") scn.atom_pdb_atomradius = EnumProperty( name="Type of radius", description="Choose type of atom radius", items=(('0', "Pre-defined", "Use pre-defined radius"), ('1', "Atomic", "Use atomic radius"), ('2', "van der Waals", "Use van der Waals radius")), - default='0',) + default='0',) # In the panel scn.atom_pdb_datafile = StringProperty( - name = "", description="Path to your custom data file", + name = "", description="Path to your custom data file", maxlen = 256, default = "", subtype='FILE_PATH') scn.atom_pdb_PDB_file = StringProperty( - name = "Path to file", default="", - description = "Path of the PDB file") + name = "Path to file", default="", + description = "Path of the PDB file") # TODO, remove this property, its used for display only! - scn.atom_pdb_number_atoms = StringProperty(name="", + scn.atom_pdb_number_atoms = StringProperty(name="", default="Number", description = "This output shows " "the number of atoms which have been loaded") scn.atom_pdb_distance = StringProperty( - name="", default="Distance (A)", - description="Distance of 2 objects in Angstrom") + name="", default="Distance (A)", + description="Distance of 2 objects in Angstrom") scn.atom_pdb_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',) - scn.atom_pdb_radius_type = EnumProperty( + default='ALL_ACTIVE',) + scn.atom_pdb_radius_type = EnumProperty( name="Type", description="Which type of atom radii?", items=(('0',"predefined", "Use pre-defined radii"), - ('1',"atomic", "Use atomic radii"), + ('1',"atomic", "Use atomic radii"), ('2',"van der Waals","Use van der Waals radii")), - default='0',update=Callback_radius_type) + default='0',update=Callback_radius_type) scn.atom_pdb_radius_pm_name = StringProperty( - name="", default="Atom name", + name="", default="Atom name", description="Put in the name of the atom (e.g. Hydrogen)") scn.atom_pdb_radius_pm = FloatProperty( - name="", default=100.0, min=0.0, - description="Put in the radius of the atom (in pm)", + name="", default=100.0, min=0.0, + description="Put in the radius of the atom (in pm)", update=Callback_radius_pm) scn.atom_pdb_radius_all = FloatProperty( - name="Scale", default = 1.05, min=1.0, + name="Scale", default = 1.05, min=1.0, description="Put in the scale factor") - - + + # Button loading a custom data file -class CLASS_atom_pdb_datafile_apply(bpy.types.Operator): +class CLASS_atom_pdb_datafile_apply(Operator): bl_idname = "atom_pdb.datafile_apply" bl_label = "Apply" bl_description = "Use color and radii values stored in a custom file" def execute(self, context): - scn = bpy.context.scene - + scn = bpy.context.scene + if scn.atom_pdb_datafile == "": - return {'FINISHED'} - + return {'FINISHED'} + import_pdb.DEF_atom_pdb_custom_datafile(scn.atom_pdb_datafile) - + + # TODO, move this into 'import_pdb' and call the function for obj in bpy.context.selected_objects: if len(obj.children) != 0: child = obj.children[0] if child.type == "SURFACE" or child.type == "MESH": - for element in ATOM_PDB_ELEMENTS: + for element in import_pdb.ATOM_PDB_ELEMENTS: if element.name in obj.name: - child.scale = (element.radii[0], - element.radii[0], - element.radii[0]) + child.scale = (element.radii[0],) * 3 child.active_material.diffuse_color = element.color else: if obj.type == "SURFACE" or obj.type == "MESH": - for element in ATOM_PDB_ELEMENTS: + for element in import_pdb.ATOM_PDB_ELEMENTS: if element.name in obj.name: - obj.scale = (element.radii[0], - element.radii[0], - element.radii[0]) + obj.scale = (element.radii[0],) * 3 obj.active_material.diffuse_color = element.color - - return {'FINISHED'} - - + + return {'FINISHED'} + + # Button for measuring the distance of the active objects -class CLASS_atom_pdb_separate_atom(bpy.types.Operator): +class CLASS_atom_pdb_separate_atom(Operator): bl_idname = "atom_pdb.separate_atom" bl_label = "Separate atom" bl_description = "Separate the atom you have chosen" def execute(self, context): scn = bpy.context.scene - + # Get first all important properties from the atom which the user # has chosen: location, color, scale obj = bpy.context.edit_object - name = obj.name - loc_obj_vec = obj.location + name = obj.name + loc_obj_vec = obj.location scale = obj.children[0].scale - material = obj.children[0].active_material - + material = obj.children[0].active_material + # Separate the vertex from the main mesh and create a new mesh. bpy.ops.mesh.separate() new_object = bpy.context.scene.objects[0] # Keep in mind the coordinates <= We only need this loc_vec = new_object.data.vertices[0].co - + # And now, switch to the OBJECT mode such that we can ... - bpy.ops.object.mode_set(mode='OBJECT', toggle=False) + bpy.ops.object.mode_set(mode='OBJECT', toggle=False) # ... delete the new mesh including the separated vertex - bpy.ops.object.select_all(action='DESELECT') + bpy.ops.object.select_all(action='DESELECT') new_object.select = True - bpy.ops.object.delete() + bpy.ops.object.delete() # TODO, use scene.objects.unlink() # Create a new atom/vacancy at the position of the old atom - current_layers=bpy.context.scene.layers - + current_layers=bpy.context.scene.layers + if "Vacancy" not in name: if scn.use_atom_pdb_mesh == False: bpy.ops.surface.primitive_nurbs_surface_sphere_add( - view_align=False, enter_editmode=False, - location=loc_vec+loc_obj_vec, - rotation=(0.0, 0.0, 0.0), - layers=current_layers) + view_align=False, enter_editmode=False, + location=loc_vec+loc_obj_vec, + rotation=(0.0, 0.0, 0.0), + layers=current_layers) else: bpy.ops.mesh.primitive_uv_sphere_add( - segments=scn.atom_pdb_mesh_azimuth, - ring_count=scn.atom_pdb_mesh_zenith, - size=1, view_align=False, enter_editmode=False, - location=loc_vec+loc_obj_vec, - rotation=(0, 0, 0), - layers=current_layers) - else: + segments=scn.atom_pdb_mesh_azimuth, + ring_count=scn.atom_pdb_mesh_zenith, + size=1, view_align=False, enter_editmode=False, + location=loc_vec+loc_obj_vec, + rotation=(0, 0, 0), + layers=current_layers) + else: bpy.ops.mesh.primitive_cube_add( - view_align=False, enter_editmode=False, - location=loc_vec+loc_obj_vec, - rotation=(0.0, 0.0, 0.0), - layers=current_layers) - + view_align=False, enter_editmode=False, + location=loc_vec+loc_obj_vec, + rotation=(0.0, 0.0, 0.0), + layers=current_layers) + new_atom = bpy.context.scene.objects.active # Scale, material and name it. new_atom.scale = scale new_atom.active_material = material new_atom.name = name + "_sep" - + # Switch back into the 'Edit mode' because we would like to seprate # other atoms may be (more convinient) new_atom.select = False obj.select = True bpy.context.scene.objects.active = obj - bpy.ops.object.select_all(action='DESELECT') - bpy.ops.object.mode_set(mode='EDIT', toggle=False) - + bpy.ops.object.select_all(action='DESELECT') + bpy.ops.object.mode_set(mode='EDIT', toggle=False) + return {'FINISHED'} # Button for measuring the distance of the active objects -class CLASS_atom_pdb_distance_button(bpy.types.Operator): +class CLASS_atom_pdb_distance_button(Operator): bl_idname = "atom_pdb.button_distance" bl_label = "Measure ..." bl_description = "Measure the distance between two objects" @@ -387,11 +385,11 @@ class CLASS_atom_pdb_distance_button(bpy.types.Operator): dist = import_pdb.DEF_atom_pdb_distance() if dist != "N.A.": - # The string length is cut, 3 digits after the first 3 digits - # after the '.'. Append also "Angstrom". - # Remember: 1 Angstrom = 10^(-10) m + # The string length is cut, 3 digits after the first 3 digits + # after the '.'. Append also "Angstrom". + # Remember: 1 Angstrom = 10^(-10) m pos = str.find(dist, ".") - dist = dist[:pos+4] + dist = dist[:pos+4] dist = dist + " A" # Put the distance into the string of the output field. @@ -400,7 +398,7 @@ class CLASS_atom_pdb_distance_button(bpy.types.Operator): # Button for increasing the radii of all atoms -class CLASS_atom_pdb_radius_all_bigger_button(bpy.types.Operator): +class CLASS_atom_pdb_radius_all_bigger_button(Operator): bl_idname = "atom_pdb.radius_all_bigger" bl_label = "Bigger ..." bl_description = "Increase the radii of the atoms" @@ -408,14 +406,14 @@ class CLASS_atom_pdb_radius_all_bigger_button(bpy.types.Operator): def execute(self, context): scn = bpy.context.scene import_pdb.DEF_atom_pdb_radius_all( - scn.atom_pdb_radius_all, + scn.atom_pdb_radius_all, scn.atom_pdb_radius_how, ) return {'FINISHED'} # Button for decreasing the radii of all atoms -class CLASS_atom_pdb_radius_all_smaller_button(bpy.types.Operator): +class CLASS_atom_pdb_radius_all_smaller_button(Operator): bl_idname = "atom_pdb.radius_all_smaller" bl_label = "Smaller ..." bl_description = "Decrease the radii of the atoms" @@ -423,36 +421,36 @@ class CLASS_atom_pdb_radius_all_smaller_button(bpy.types.Operator): def execute(self, context): scn = bpy.context.scene import_pdb.DEF_atom_pdb_radius_all( - 1.0/scn.atom_pdb_radius_all, + 1.0/scn.atom_pdb_radius_all, scn.atom_pdb_radius_how, ) return {'FINISHED'} # The button for loading the atoms and creating the scene -class CLASS_atom_pdb_load_button(bpy.types.Operator): +class CLASS_atom_pdb_load_button(Operator): bl_idname = "atom_pdb.button_reload" bl_label = "RELOAD" bl_description = "Load the structure again" - + def execute(self, context): scn = bpy.context.scene azimuth = scn.atom_pdb_mesh_azimuth - zenith = scn.atom_pdb_mesh_zenith + zenith = scn.atom_pdb_mesh_zenith bradius = scn.atom_pdb_scale_ballradius bdistance = scn.atom_pdb_scale_distances radiustype = scn.atom_pdb_atomradius - center = scn.use_atom_pdb_center - sticks = scn.use_atom_pdb_sticks + center = scn.use_atom_pdb_center + sticks = scn.use_atom_pdb_sticks ssector = scn.atom_pdb_sticks_sectors sradius = scn.atom_pdb_sticks_radius - cam = scn.use_atom_pdb_cam + cam = scn.use_atom_pdb_cam lamp = scn.use_atom_pdb_lamp - mesh = scn.use_atom_pdb_mesh + mesh = scn.use_atom_pdb_mesh datafile = scn.atom_pdb_datafile - - # Execute main routine an other time ... from the panel + + # Execute main routine an other time ... from the panel atom_number = import_pdb.DEF_atom_pdb_main( mesh, azimuth, zenith, bradius, radiustype, bdistance, sticks, @@ -464,72 +462,69 @@ class CLASS_atom_pdb_load_button(bpy.types.Operator): # This is the class for the file dialog. -class CLASS_LoadPDB(bpy.types.Operator, ImportHelper): - bl_idname = "import_pdb.pdb" - bl_label = "Import PDB" - +class ImportPDB(Operator, ImportHelper): + bl_idname = "import_mesh.pdb" + bl_label = "Import Protein Data Bank (*.pdb)" + filename_ext = ".pdb" filter_glob = StringProperty(default="*.pdb", options={'HIDDEN'},) def draw(self, context): - layout = self.layout + layout = self.layout scn = bpy.context.scene row = layout.row() row.prop(scn, "use_atom_pdb_cam") - row.prop(scn, "use_atom_pdb_lamp") - row = layout.row() - col = row.column() + row.prop(scn, "use_atom_pdb_lamp") + row = layout.row() + col = row.column() col.prop(scn, "use_atom_pdb_mesh") - col = row.column(align=True) + col = row.column(align=True) col.prop(scn, "atom_pdb_mesh_azimuth") - col.prop(scn, "atom_pdb_mesh_zenith") - - row = layout.row() - col = row.column() + col.prop(scn, "atom_pdb_mesh_zenith") + + row = layout.row() + col = row.column() col.label(text="Scaling factors") col = row.column(align=True) col.prop(scn, "atom_pdb_scale_ballradius") col.prop(scn, "atom_pdb_scale_distances") - row = layout.row() + row = layout.row() col = row.column() col.prop(scn, "use_atom_pdb_sticks") col = row.column(align=True) col.prop(scn, "atom_pdb_sticks_sectors") col.prop(scn, "atom_pdb_sticks_radius") - row = layout.row() + row = layout.row() row.prop(scn, "use_atom_pdb_center") - - row = layout.row() + + row = layout.row() row.prop(scn, "atom_pdb_atomradius") - - def execute(self, context): - global ATOM_PDB_ELEMENTS_DEFAULT - global ATOM_PDB_ELEMENTS + def execute(self, context): scn = bpy.context.scene # This is in order to solve this strange 'relative path' thing. import_pdb.ATOM_PDB_FILEPATH = bpy.path.abspath(self.filepath) scn.atom_pdb_PDB_file = import_pdb.ATOM_PDB_FILEPATH - + azimuth = scn.atom_pdb_mesh_azimuth - zenith = scn.atom_pdb_mesh_zenith + zenith = scn.atom_pdb_mesh_zenith bradius = scn.atom_pdb_scale_ballradius bdistance = scn.atom_pdb_scale_distances radiustype = scn.atom_pdb_atomradius - center = scn.use_atom_pdb_center - sticks = scn.use_atom_pdb_sticks + center = scn.use_atom_pdb_center + sticks = scn.use_atom_pdb_sticks ssector = scn.atom_pdb_sticks_sectors sradius = scn.atom_pdb_sticks_radius - cam = scn.use_atom_pdb_cam + cam = scn.use_atom_pdb_cam lamp = scn.use_atom_pdb_lamp - mesh = scn.use_atom_pdb_mesh + mesh = scn.use_atom_pdb_mesh datafile = scn.atom_pdb_datafile - # Execute main routine + # Execute main routine atom_number = import_pdb.DEF_atom_pdb_main( mesh, azimuth, zenith, bradius, radiustype, bdistance, sticks, @@ -542,33 +537,17 @@ class CLASS_LoadPDB(bpy.types.Operator, ImportHelper): # The entry into the menu 'file -> import' def menu_func(self, context): - self.layout.operator(CLASS_LoadPDB.bl_idname, text="PDB (.pdb)") + self.layout.operator(ImportPDB.bl_idname, text="Protein Data Bank (.pdb)") def register(): - bpy.utils.register_class(CLASS_atom_pdb_panel) - bpy.utils.register_class(CLASS_atom_pdb_datafile_apply) - bpy.utils.register_class(CLASS_atom_pdb_IO) - bpy.utils.register_class(CLASS_atom_pdb_load_button) - bpy.utils.register_class(CLASS_atom_pdb_radius_all_bigger_button) - bpy.utils.register_class(CLASS_atom_pdb_radius_all_smaller_button) - bpy.utils.register_class(CLASS_atom_pdb_distance_button) - bpy.utils.register_class(CLASS_atom_pdb_separate_atom) bpy.utils.register_module(__name__) bpy.types.INFO_MT_file_import.append(menu_func) def unregister(): - bpy.utils.unregister_class(CLASS_atom_pdb_panel) - bpy.utils.unregister_class(CLASS_atom_pdb_datafile_apply) - bpy.utils.unregister_class(CLASS_atom_pdb_IO) - bpy.utils.unregister_class(CLASS_atom_pdb_load_button) - bpy.utils.unregister_class(CLASS_atom_pdb_radius_all_bigger_button) - bpy.utils.unregister_class(CLASS_atom_pdb_radius_all_smaller_button) - bpy.utils.unregister_class(CLASS_atom_pdb_distance_button) - bpy.utils.unregister_class(CLASS_atom_pdb_separate_atom) - bpy.utils.unregister_module(__name__) + bpy.utils.unregister_module(__name__) bpy.types.INFO_MT_file_import.remove(menu_func) - + if __name__ == "__main__": - + register() diff --git a/io_mesh_pdb/import_pdb.py b/io_mesh_pdb/import_pdb.py index eff89985..ecf50204 100644 --- a/io_mesh_pdb/import_pdb.py +++ b/io_mesh_pdb/import_pdb.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# +# # # Authors : Clemens Barth (Blendphys@root-1.de), ... # @@ -27,13 +27,12 @@ # First publication in Blender : 2011-11-11 # Last modified : 2011-12-01 # -# Acknowledgements: Thanks to ideasman, meta_androcto, truman, kilon, -# dairin0d, PKHG, Valter, etc +# Acknowledgements: Thanks to ideasman, meta_androcto, truman, kilon, +# dairin0d, PKHG, Valter, etc # import bpy import io -import sys import math import os from math import pi, cos, sin @@ -41,7 +40,7 @@ from mathutils import Vector, Matrix # These are variables, which contain the name of the PDB file and # the path of the PDB file. -# They are used almost everywhere, which is the reason why they +# They are used almost everywhere, which is the reason why they # should stay global. First, they are empty and get 'filled' directly # after having chosen the PDB file (see 'class LoadPDB' further below). @@ -55,14 +54,14 @@ ATOM_PDB_STRING = "Atomic Blender\n===================" # Atom, stick and element data -# This is a list that contains some data of all possible elements. The structure +# This is a list that contains some data of all possible elements. The structure # is as follows: # # 1, "Hydrogen", "H", [0.0,0.0,1.0], 0.32, 0.32, 0.32 , -1 , 1.54 means # # No., name, short name, color, radius (used), radius (covalent), radius (atomic), -# -# charge state 1, radius (ionic) 1, charge state 2, radius (ionic) 2, ... all +# +# charge state 1, radius (ionic) 1, charge state 2, radius (ionic) 2, ... all # charge states for any atom are listed, if existing. # The list is fixed and cannot be changed ... (see below) @@ -175,17 +174,17 @@ ATOM_PDB_ELEMENTS_DEFAULT = ( (106, "Stick", "Stick", ( 0.5, 0.5, 0.5), 1.00, 1.00, 1.00), ) -# This list here contains all data of the elements and will be used during -# runtime. It is a list of classes. +# This list here contains all data of the elements and will be used during +# runtime. It is a list of classes. # During executing Atomic Blender, the list will be initialized with the fixed # data from above via the class structure below (CLASS_atom_pdb_Elements). We # have then one fixed list (above), which will never be changed, and a list of -# classes with same data. The latter can be modified via loading a separate -# custom data file. +# classes with same data. The latter can be modified via loading a separate +# custom data file. ATOM_PDB_ELEMENTS = [] # This is the class, which stores the properties for one element. -class CLASS_atom_pdb_Elements: +class CLASS_atom_pdb_Elements: # TODO, use __slots__ def __init__(self, number, name,short_name, color, radii, radii_ionic): self.number = number self.name = name @@ -193,9 +192,9 @@ class CLASS_atom_pdb_Elements: self.color = color self.radii = radii self.radii_ionic = radii_ionic - -# This is the class, which stores the properties of one atom. -class CLASS_atom_pdb_atom: + +# This is the class, which stores the properties of one atom. +class CLASS_atom_pdb_atom: # TODO, use __slots__ def __init__(self, element, name, location, radius, color, material): self.element = element self.name = name @@ -203,21 +202,21 @@ class CLASS_atom_pdb_atom: self.radius = radius self.color = color self.material = material - -# This is the class, which stores the two atoms of one stick. -class CLASS_atom_pdb_stick: + +# This is the class, which stores the two atoms of one stick. +class CLASS_atom_pdb_stick: # TODO, use __slots__ def __init__(self, atom1, atom2): self.atom1 = atom1 - self.atom2 = atom2 + self.atom2 = atom2 # ----------------------------------------------------------------------------- # Some small routines -# Routine which produces a cylinder. All is somewhat easy to undertsand. +# Routine which produces a cylinder. All is somewhat easy to undertsand. def DEF_atom_pdb_build_stick(radius, length, sectors): - + vertices = [] faces = [] @@ -229,7 +228,7 @@ def DEF_atom_pdb_build_stick(radius, length, sectors): for i in range(sectors-1): x = radius * cos( dphi * i ) y = radius * sin( dphi * i ) - z = length / 2.0 + z = length / 2.0 vertex = Vector((x,y,z)) vertices_top.append(vertex) z = -length / 2.0 @@ -251,12 +250,12 @@ def DEF_atom_pdb_build_stick(radius, length, sectors): faces.append(face_top) faces.append(face_bottom) - # Side facets + # Side facets for i in range(sectors-1): if i == sectors-2: - faces.append( [i+1, 1, 1+sectors, i+1+sectors] ) + faces.append( [i+1, 1, 1+sectors, i+1+sectors] ) else: - faces.append( [i+1, i+2, i+2+sectors, i+1+sectors] ) + faces.append( [i+1, i+2, i+2+sectors, i+1+sectors] ) # Build the mesh cylinder = bpy.data.meshes.new("Sticks_Cylinder") @@ -264,11 +263,11 @@ def DEF_atom_pdb_build_stick(radius, length, sectors): cylinder.update() new_cylinder = bpy.data.objects.new("Sticks_Cylinder", cylinder) bpy.context.scene.objects.link(new_cylinder) - + return new_cylinder -# This function measures the distance between two objects (atoms), +# This function measures the distance between two objects (atoms), # which are active. def DEF_atom_pdb_distance(): @@ -279,147 +278,131 @@ def DEF_atom_pdb_distance(): return "N.A." dv = object_2.location - object_1.location - return str(dv.length) + return str(dv.length) -# Routine to modify the radii via the type: +# Routine to modify the radii via the type: # pre-defined, atomic or van der Waals # Explanations here are also valid for the next 3 DEFs. def DEF_atom_pdb_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 = [] + + # 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) - + 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 ATOM_PDB_ELEMENTS: + for element in ATOM_PDB_ELEMENTS: if element.name in obj.name: - obj.children[0].scale = (element.radii[int(rtype)], - element.radii[int(rtype)], - element.radii[int(rtype)]) + obj.children[0].scale = (element.radii[int(rtype)],) * 3 else: if obj.type == "SURFACE" or obj.type == "MESH": - for element in ATOM_PDB_ELEMENTS: + for element in ATOM_PDB_ELEMENTS: if element.name in obj.name: - obj.scale = (element.radii[int(rtype)], - element.radii[int(rtype)], - element.radii[int(rtype)]) + obj.scale = (element.radii[int(rtype)],) * 3 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": - for element in ATOM_PDB_ELEMENTS: + for element in ATOM_PDB_ELEMENTS: if element.name in obj.name: - obj.children[0].scale = (element.radii[int(rtype)], - element.radii[int(rtype)], - element.radii[int(rtype)]) + obj.children[0].scale = (element.radii[int(rtype)],) * 3 else: if obj.type == "SURFACE" or obj.type == "MESH": - for element in ATOM_PDB_ELEMENTS: + for element in ATOM_PDB_ELEMENTS: if element.name in obj.name: - obj.scale = (element.radii[int(rtype)], - element.radii[int(rtype)], - element.radii[int(rtype)]) - + obj.scale = (element.radii[int(rtype)],) * 3 + # Routine to modify the radii in picometer of a specific type of atom def DEF_atom_pdb_radius_pm(atomname, radius_pm, how): - + if how == "ALL_IN_LAYER": - + layers = [] for i in range(20): if bpy.context.scene.layers[i] == True: layers.append(i) - - change_objects = [] + + change_objects = [] for obj in bpy.context.scene.objects: for layer in layers: if obj.layers[layer] == True: - change_objects.append(obj) - + 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 atomname in obj.name: - obj.children[0].scale = (radius_pm/100, - radius_pm/100, - radius_pm/100) + obj.children[0].scale = (radius_pm/100,) * 3 else: if obj.type == "SURFACE" or obj.type == "MESH": if atomname in obj.name: - obj.scale = (radius_pm/100, - radius_pm/100, - radius_pm/100) + obj.scale = (radius_pm/100,) * 3 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 atomname in obj.name: - obj.children[0].scale = (radius_pm/100, - radius_pm/100, - radius_pm/100) + obj.children[0].scale = (radius_pm/100,) * 3 else: if obj.type == "SURFACE" or obj.type == "MESH": if atomname in obj.name: - obj.scale = (radius_pm/100, - radius_pm/100, - radius_pm/100) + obj.scale = (radius_pm/100,) * 3 # Routine to scale the radii of all atoms def DEF_atom_pdb_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 = [] + + 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 + obj.children[0].scale *= scale else: if obj.type == "SURFACE" or obj.type == "MESH": if "Stick" not in obj.name: - obj.scale *= scale + 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 + obj.children[0].scale *= scale else: if obj.type == "SURFACE" or obj.type == "MESH": if "Stick" not in obj.name: - obj.scale *= scale + obj.scale *= scale # This reads a custom data file. @@ -432,11 +415,11 @@ def DEF_atom_pdb_custom_datafile(path_datafile): if os.path.isfile(path_datafile) == False: return False - - # The whole list gets deleted! We build it new. + + # The whole list gets deleted! We build it new. ATOM_PDB_ELEMENTS[:] = [] - # Read the data file, which contains all data + # Read the data file, which contains all data # (atom name, radii, colors, etc.) data_file_p = io.open(path_datafile, "r") @@ -445,7 +428,7 @@ def DEF_atom_pdb_custom_datafile(path_datafile): if "Atom" in line: line = data_file_p.readline() - + # Number line = data_file_p.readline() number = line[19:-1] @@ -470,17 +453,17 @@ def DEF_atom_pdb_custom_datafile(path_datafile): # Van der Waals radius line = data_file_p.readline() radius_vdW = float(line[19:-1]) - + radii = [radius_used,radius_atomic,radius_vdW] radii_ionic = [] - + element = CLASS_atom_pdb_Elements(number,name,short_name,color, - radii, radii_ionic) - - ATOM_PDB_ELEMENTS.append(element) + radii, radii_ionic) + + ATOM_PDB_ELEMENTS.append(element) data_file_p.close() - + return True @@ -492,18 +475,18 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, Ball_radius_factor,radiustype,Ball_distance_factor, use_stick,Stick_sectors,Stick_diameter,put_to_center, use_camera,use_lamp,path_datafile): - + # The list of all atoms as read from the PDB file. all_atoms = [] - + # The list of all sticks. all_sticks = [] - + # List of materials atom_material_list = [] # A list of ALL objects which are loaded (needed for selecting the loaded - # structure. + # structure. atom_object_list = [] @@ -513,15 +496,15 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, ATOM_PDB_ELEMENTS[:] = [] for item in ATOM_PDB_ELEMENTS_DEFAULT: - + # All three radii into a list radii = [item[4],item[5],item[6]] # The handling of the ionic radii will be done later. So far, it is an # empty list. - radii_ionic = [] + radii_ionic = [] li = CLASS_atom_pdb_Elements(item[0],item[1],item[2],item[3], - radii,radii_ionic) + radii,radii_ionic) ATOM_PDB_ELEMENTS.append(li) @@ -542,31 +525,31 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, break if "HETATM" in split_list[0]: break - + j = 0 # This is in fact an endless 'while loop', ... while j > -1: # ... the loop is broken here (EOF) ... if line == "": - break + break # If there is a "TER" we need to put empty entries into the lists # in order to not destroy the order of atom numbers and same numbers - # used for sticks. "TER? What is that?" TER indicates the end of a + # used for sticks. "TER? What is that?" TER indicates the end of a # list of ATOM/HETATM records for a chain. if "TER" in line: short_name = "TER" name = "TER" radius = 0.0 color = [0,0,0] - location = Vector((0,0,0)) + location = Vector((0,0,0)) # Append the TER into the list. Material remains empty so far. - all_atoms.append(CLASS_atom_pdb_atom(short_name, - name, - location, - radius, - color,[])) + all_atoms.append(CLASS_atom_pdb_atom(short_name, + name, + location, + radius, + color,[])) # If 'ATOM or 'HETATM' appears in the line then do ... elif "ATOM" in line or "HETATM" in line: @@ -575,31 +558,31 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, short_name = line[13:14] if short_name.isupper() == True: if line[14:15].islower() == True: - short_name = short_name + line[14:15] - else: + short_name = short_name + line[14:15] + else: short_name = line[12:13] if short_name.isupper() == True: if line[13:14].islower() == True: - short_name = short_name + line[13:14] + short_name = short_name + line[13:14] # ... to here. - - # Go through all elements and find the element of the current atom. + + # Go through all elements and find the element of the current atom. FLAG_FOUND = False for element in ATOM_PDB_ELEMENTS: if str.upper(short_name) == str.upper(element.short_name): # Give the atom its proper names, color and radius: short_name = str.upper(element.short_name) name = element.name - # int(radiustype) => type of radius: + # int(radiustype) => type of radius: # pre-defined (0), atomic (1) or van der Waals (2) radius = float(element.radii[int(radiustype)]) color = element.color FLAG_FOUND = True break - # Is it a vacancy or an 'unknown atom' ? + # Is it a vacancy or an 'unknown atom' ? if FLAG_FOUND == False: - # Give this atom also a name. If it is an 'X' then it is a + # Give this atom also a name. If it is an 'X' then it is a # vacancy. Otherwise ... if "X" in short_name: short_name = "VAC" @@ -607,30 +590,30 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, radius = float(ATOM_PDB_ELEMENTS[-3].radii[int(radiustype)]) color = ATOM_PDB_ELEMENTS[-3].color # ... take what is written in the PDB file. These are somewhat - # unknown atoms. This should never happen, the element list is + # unknown atoms. This should never happen, the element list is # almost complete. However, we do this due to security reasons. else: short_name = str.upper(short_name) name = str.upper(short_name) radius = float(ATOM_PDB_ELEMENTS[-2].radii[int(radiustype)]) - color = ATOM_PDB_ELEMENTS[-2].color - + color = ATOM_PDB_ELEMENTS[-2].color + # x,y and z are at fixed positions in the PDB file. x = float(line[30:38].rsplit()[0]) y = float(line[38:46].rsplit()[0]) z = float(line[46:55].rsplit()[0]) - - location = Vector((x,y,z)) - - j += 1 + + location = Vector((x,y,z)) + + j += 1 # Append the atom to the list. Material remains empty so far. - all_atoms.append(CLASS_atom_pdb_atom(short_name, - name, - location, - radius, - color,[])) - + all_atoms.append(CLASS_atom_pdb_atom(short_name, + name, + location, + radius, + color,[])) + line = ATOM_PDB_FILEPATH_p.readline() line = line[:-1] @@ -644,14 +627,14 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, # The list that contains info about all types of atoms is created - # here. It is used for building the material properties for - # instance (see below). + # here. It is used for building the material properties for + # instance (see below). atom_all_types_list = [] - + for atom in all_atoms: FLAG_FOUND = False for atom_type in atom_all_types_list: - # If the atom name is already in the list, FLAG on 'True'. + # If the atom name is already in the list, FLAG on 'True'. if atom_type[0] == atom.name: FLAG_FOUND = True break @@ -661,28 +644,28 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, # name (e.g. 'Sodium') and its color. atom_all_types_list.append([atom.name, atom.element, atom.color]) - # The list of materials is built. - # Note that all atoms of one type (e.g. all hydrogens) get only ONE - # material! This is good because then, by activating one atom in the - # Blender scene and changing the color of this atom, one changes the color + # The list of materials is built. + # Note that all atoms of one type (e.g. all hydrogens) get only ONE + # material! This is good because then, by activating one atom in the + # Blender scene and changing the color of this atom, one changes the color # of ALL atoms of the same type at the same time. - - # Create first a new list of materials for each type of atom + + # Create first a new list of materials for each type of atom # (e.g. hydrogen) - for atom_type in atom_all_types_list: + for atom_type in atom_all_types_list: material = bpy.data.materials.new(atom_type[1]) material.name = atom_type[0] material.diffuse_color = atom_type[2] atom_material_list.append(material) - - # Now, we go through all atoms and give them a material. For all atoms ... + + # Now, we go through all atoms and give them a material. For all atoms ... for atom in all_atoms: # ... and all materials ... for material in atom_material_list: - # ... select the correct material for the current atom via + # ... select the correct material for the current atom via # comparison of names ... if atom.name in material.name: - # ... and give the atom its material properties. + # ... and give the atom its material properties. # However, before we check, if it is a vacancy, because then it # gets some additional preparation. The vacancy is represented # by a transparent cube. @@ -690,15 +673,15 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, material.transparency_method = 'Z_TRANSPARENCY' material.alpha = 1.3 material.raytrace_transparency.fresnel = 1.6 - material.raytrace_transparency.fresnel_factor = 1.6 - material.use_transparency = True + material.raytrace_transparency.fresnel_factor = 1.6 + material.use_transparency = True # The atom gets its properties. - atom.material = material + atom.material = material # ------------------------------------------------------------------------ # READING DATA OF STICKS - + # Open the PDB file again such that the file pointer is in the first # line ... . Stupid, I know ... ;-) @@ -712,73 +695,73 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, split_list = line.split(' ') if "CONECT" in split_list[0]: break - + Number_of_sticks = 0 sticks_double = 0 j = 0 - # This is in fact an endless while loop, ... + # This is in fact an endless while loop, ... while j > -1: - + # ... which is broken here (EOF) ... if line == "": - break + break # ... or here, when no 'CONECT' appears anymore. if "CONECT" not in line: break - - # The strings of the atom numbers do have a clear position in the file - # (From 7 to 12, from 13 to 18 and so on.) and one needs to consider - # this. One could also use the split function but then one gets into - # trouble if there are many atoms: For instance, it may happen that one + + # The strings of the atom numbers do have a clear position in the file + # (From 7 to 12, from 13 to 18 and so on.) and one needs to consider + # this. One could also use the split function but then one gets into + # trouble if there are many atoms: For instance, it may happen that one # has # CONECT 11111 22244444 # - # In Fact it means that atom No. 11111 has a connection with atom - # No. 222 but also with atom No. 44444. The split function would give - # me only two numbers (11111 and 22244444), which is wrong. - + # In Fact it means that atom No. 11111 has a connection with atom + # No. 222 but also with atom No. 44444. The split function would give + # me only two numbers (11111 and 22244444), which is wrong. + # Cut spaces from the right and 'CONECT' at the beginning - line = line.rstrip() + line = line.rstrip() line = line[6:] # Amount of loops length = len(line) loops = int(length/5) - + # List of atoms atom_list = [] for i in range(loops): number = line[5*i:5*(i+1)].rsplit() - if number != []: + if number != []: if number[0].isdigit() == True: atom_number = int(number[0]) atom_list.append(atom_number) - + # The first atom is connected with all the others in the list. atom1 = atom_list[0] - + # For all the other atoms in the list do: for each_atom in atom_list[1:]: - + # The second, third, ... partner atom atom2 = each_atom # Note that in a PDB file, sticks of one atom pair can appear a - # couple of times. (Only god knows why ...) + # couple of times. (Only god knows why ...) # So, does a stick between the considered atoms already exist? FLAG_BAR = False for k in range(Number_of_sticks): - if ((all_sticks[k].atom1 == atom1 and all_sticks[k].atom2 == atom2) or + if ((all_sticks[k].atom1 == atom1 and all_sticks[k].atom2 == atom2) or (all_sticks[k].atom2 == atom1 and all_sticks[k].atom1 == atom2)): sticks_double += 1 # If yes, then FLAG on 'True'. FLAG_BAR = True break - # If the stick is not yet registered (FLAG_BAR == False), then + # If the stick is not yet registered (FLAG_BAR == False), then # register it! if FLAG_BAR == False: all_sticks.append(CLASS_atom_pdb_stick(atom1,atom2)) - Number_of_sticks += 1 + Number_of_sticks += 1 j += 1 line = ATOM_PDB_FILEPATH_p.readline() @@ -795,10 +778,10 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, # It may happen that the structure in a PDB file already has an offset # If chosen, the structure is first put into the center of the scene # (the offset is substracted). - + if put_to_center == True: - sum_vec = Vector((0.0,0.0,0.0)) + sum_vec = Vector((0.0,0.0,0.0)) # Sum of all atom coordinates sum_vec = sum([atom.location for atom in all_atoms], sum_vec) @@ -809,61 +792,61 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, # After, for each atom the center of gravity is substracted for atom in all_atoms: atom.location -= sum_vec - + # ------------------------------------------------------------------------ - # SCALING + # SCALING + - # Take all atoms and adjust their radii and scale the distances. for atom in all_atoms: atom.location *= Ball_distance_factor - - + + # ------------------------------------------------------------------------ # DETERMINATION OF SOME GEOMETRIC PROPERTIES - - # In the following, some geometric properties of the whole object are - # determined: center, size, etc. + + # In the following, some geometric properties of the whole object are + # determined: center, size, etc. sum_vec = Vector((0.0,0.0,0.0)) # First the center is determined. All coordinates are summed up ... sum_vec = sum([atom.location for atom in all_atoms], sum_vec) - + # ... and the average is taken. This gives the center of the object. object_center_vec = sum_vec / Number_of_total_atoms - # Now, we determine the size.The farest atom from the object center is + # Now, we determine the size.The farest atom from the object center is # taken as a measure. The size is used to place well the camera and light - # into the scene. - object_size_vec = [atom.location - object_center_vec for atom in all_atoms] + # into the scene. + object_size_vec = [atom.location - object_center_vec for atom in all_atoms] object_size = 0.0 object_size = max(object_size_vec).length # ------------------------------------------------------------------------ # CAMERA AND LAMP - + camera_factor = 15.0 # If chosen a camera is put into the scene. if use_camera == True: - # Assume that the object is put into the global origin. Then, the - # camera is moved in x and z direction, not in y. The object has its - # size at distance math.sqrt(object_size) from the origin. So, move the - # camera by this distance times a factor of camera_factor in x and z. - # Then add x, y and z of the origin of the object. - object_camera_vec = Vector((math.sqrt(object_size) * camera_factor, - 0.0, + # Assume that the object is put into the global origin. Then, the + # camera is moved in x and z direction, not in y. The object has its + # size at distance math.sqrt(object_size) from the origin. So, move the + # camera by this distance times a factor of camera_factor in x and z. + # Then add x, y and z of the origin of the object. + object_camera_vec = Vector((math.sqrt(object_size) * camera_factor, + 0.0, math.sqrt(object_size) * camera_factor)) camera_xyz_vec = object_center_vec + object_camera_vec # Create the camera current_layers=bpy.context.scene.layers - bpy.ops.object.camera_add(view_align=False, enter_editmode=False, - location=camera_xyz_vec, + bpy.ops.object.camera_add(view_align=False, enter_editmode=False, + location=camera_xyz_vec, rotation=(0.0, 0.0, 0.0), layers=current_layers) # Some properties of the camera are changed. camera = bpy.context.scene.objects.active @@ -872,7 +855,7 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, camera.data.lens = 45 camera.data.clip_end = 500.0 - # Here the camera is rotated such it looks towards the center of + # Here the camera is rotated such it looks towards the center of # the object. The [0.0, 0.0, 1.0] vector along the z axis z_axis_vec = Vector((0.0, 0.0, 1.0)) # The angle between the last two vectors @@ -884,21 +867,21 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, euler = Matrix.Rotation(angle, 4, axis_vec).to_euler() camera.rotation_euler = euler - # Rotate the camera around its axis by 90° such that we have a nice + # Rotate the camera around its axis by 90° such that we have a nice # camera position and view onto the object. - bpy.ops.transform.rotate(value=(90.0*2*math.pi/360.0,), - axis=object_camera_vec, - constraint_axis=(False, False, False), - constraint_orientation='GLOBAL', - mirror=False, proportional='DISABLED', - proportional_edit_falloff='SMOOTH', - proportional_size=1, snap=False, - snap_target='CLOSEST', snap_point=(0, 0, 0), - snap_align=False, snap_normal=(0, 0, 0), + bpy.ops.transform.rotate(value=(90.0*2*math.pi/360.0,), + axis=object_camera_vec, + constraint_axis=(False, False, False), + constraint_orientation='GLOBAL', + mirror=False, proportional='DISABLED', + proportional_edit_falloff='SMOOTH', + proportional_size=1, snap=False, + snap_target='CLOSEST', snap_point=(0, 0, 0), + snap_align=False, snap_normal=(0, 0, 0), release_confirm=False) - # This does not work, I don't know why. + # This does not work, I don't know why. # #for area in bpy.context.screen.areas: # if area.type == 'VIEW_3D': @@ -908,39 +891,39 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, # Here a lamp is put into the scene, if chosen. if use_lamp == True: - # This is the distance from the object measured in terms of % + # This is the distance from the object measured in terms of % # of the camera distance. It is set onto 50% (1/2) distance. lamp_dl = math.sqrt(object_size) * 15 * 0.5 # This is a factor to which extend the lamp shall go to the right # (from the camera point of view). lamp_dy_right = lamp_dl * (3.0/4.0) - + # Create x, y and z for the lamp. object_lamp_vec = Vector((lamp_dl,lamp_dy_right,lamp_dl)) - lamp_xyz_vec = object_center_vec + object_lamp_vec + lamp_xyz_vec = object_center_vec + object_lamp_vec # Create the lamp current_layers=bpy.context.scene.layers - bpy.ops.object.lamp_add (type = 'POINT', view_align=False, - location=lamp_xyz_vec, - rotation=(0.0, 0.0, 0.0), + bpy.ops.object.lamp_add (type = 'POINT', view_align=False, + location=lamp_xyz_vec, + rotation=(0.0, 0.0, 0.0), layers=current_layers) # Some properties of the lamp are changed. lamp = bpy.context.scene.objects.active lamp.data.name = "A_lamp" lamp.name = "A_lamp" - lamp.data.distance = 500.0 - lamp.data.energy = 3.0 + lamp.data.distance = 500.0 + lamp.data.energy = 3.0 lamp.data.shadow_method = 'RAY_SHADOW' bpy.context.scene.world.light_settings.use_ambient_occlusion = True bpy.context.scene.world.light_settings.ao_factor = 0.2 - - + + # ------------------------------------------------------------------------ # SOME OUTPUT ON THE CONSOLE - - + + print() print() print() @@ -957,35 +940,35 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, # SORTING THE ATOMS - # Lists of atoms of one type are created. Example: - # draw_all_atoms = [ data_hydrogen,data_carbon,data_nitrogen ] + # Lists of atoms of one type are created. Example: + # draw_all_atoms = [ data_hydrogen,data_carbon,data_nitrogen ] # data_hydrogen = [["Hydrogen", Material_Hydrogen, Vector((x,y,z)), 109], ...] - + draw_all_atoms = [] # Go through the list which contains all types of atoms. It is the list, - # which has been created on the top during reading the PDB file. + # which has been created on the top during reading the PDB file. # Example: atom_all_types_list = ["hydrogen", "carbon", ...] for atom_type in atom_all_types_list: - + # Don't draw 'TER atoms'. if atom_type[0] == "TER": continue - - # This is the draw list, which contains all atoms of one type (e.g. + + # This is the draw list, which contains all atoms of one type (e.g. # all hydrogens) ... - draw_all_atoms_type = [] - + draw_all_atoms_type = [] + # Go through all atoms ... for atom in all_atoms: # ... select the atoms of the considered type via comparison ... if atom.name == atom_type[0]: # ... and append them to the list 'draw_all_atoms_type'. - draw_all_atoms_type.append([atom.name, - atom.material, + draw_all_atoms_type.append([atom.name, + atom.material, atom.location, atom.radius]) - + # Now append the atom list to the list of all types of atoms draw_all_atoms.append(draw_all_atoms_type) @@ -995,8 +978,7 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, # This is the number of all atoms which are put into the scene. - number_loaded_atoms = 0 - bpy.ops.object.select_all(action='DESELECT') + bpy.ops.object.select_all(action='DESELECT') # For each list of atoms of ONE type (e.g. Hydrogen) for draw_all_atoms_type in draw_all_atoms: @@ -1019,60 +1001,58 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, # Now, build a representative sphere (atom) current_layers=bpy.context.scene.layers - + if atom[0] == "Vacancy": bpy.ops.mesh.primitive_cube_add( - view_align=False, enter_editmode=False, - location=(0.0, 0.0, 0.0), - rotation=(0.0, 0.0, 0.0), + view_align=False, enter_editmode=False, + location=(0.0, 0.0, 0.0), + rotation=(0.0, 0.0, 0.0), layers=current_layers) else: # NURBS balls - if use_mesh == False: + if use_mesh == False: 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), + view_align=False, enter_editmode=False, + location=(0,0,0), rotation=(0.0, 0.0, 0.0), layers=current_layers) # UV balls else: bpy.ops.mesh.primitive_uv_sphere_add( - segments=Ball_azimuth, ring_count=Ball_zenith, - size=1, view_align=False, enter_editmode=False, - location=(0,0,0), rotation=(0, 0, 0), + segments=Ball_azimuth, ring_count=Ball_zenith, + size=1, view_align=False, enter_editmode=False, + location=(0,0,0), rotation=(0, 0, 0), layers=current_layers) - + ball = bpy.context.scene.objects.active - ball.scale = (atom[3]*Ball_radius_factor, - atom[3]*Ball_radius_factor, - atom[3]*Ball_radius_factor) - + ball.scale = (atom[3]*Ball_radius_factor,) * 3 + if atom[0] == "Vacancy": ball.name = "Cube_"+atom[0] else: ball.name = "Ball (NURBS)_"+atom[0] - ball.active_material = atom[1] + ball.active_material = atom[1] ball.parent = new_atom_mesh new_atom_mesh.dupli_type = 'VERTS' # The object is back translated to 'object_center_vec'. new_atom_mesh.location = object_center_vec atom_object_list.append(new_atom_mesh) - print() - - + print() + + # ------------------------------------------------------------------------ # DRAWING THE STICKS if use_stick == True and all_sticks != []: - + # Create a new material with the corresponding color. The # color is taken from the all_atom list, it is the last entry # in the data file (index -1). bpy.ops.object.material_slot_add() - stick_material = bpy.data.materials.new(ATOM_PDB_ELEMENTS[-1].name) + stick_material = bpy.data.materials.new(ATOM_PDB_ELEMENTS[-1].name) stick_material.diffuse_color = ATOM_PDB_ELEMENTS[-1].color - + vertices = [] faces = [] dl = 0.2 @@ -1080,26 +1060,26 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, i = 0 # For all sticks, do ... for stick in all_sticks: - + # What follows is school mathematics! :-) v1 = all_atoms[stick.atom2-1].location v2 = all_atoms[stick.atom1-1].location - + dv = (v1 - v2) - + n = dv / dv.length - m = v1 - dv / 2.0 - + # m = v1 - dv / 2.0 # UNUSED + gamma = -n * v1 b = v1 + gamma * n n_b = b / b.length - + loops = int(dv.length / dl) - + for j in range(loops): - + g = v1 - n * dl / 2.0 - n * dl * j - + p1 = g + n_b * Stick_diameter p2 = g - n_b * Stick_diameter p3 = g - n_b.cross(n) * Stick_diameter @@ -1110,17 +1090,17 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, vertices.append(p3) vertices.append(p4) faces.append((i*4+0,i*4+2,i*4+1,i*4+3)) - i += 1 - + i += 1 + mesh = bpy.data.meshes.new("Sticks") mesh.from_pydata(vertices, [], faces) mesh.update() new_mesh = bpy.data.objects.new("Sticks", mesh) - bpy.context.scene.objects.link(new_mesh) - + bpy.context.scene.objects.link(new_mesh) + current_layers = bpy.context.scene.layers stick_cylinder = DEF_atom_pdb_build_stick(Stick_diameter, dl, Stick_sectors) - + stick_cylinder.active_material = stick_material stick_cylinder.parent = new_mesh @@ -1130,7 +1110,7 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, # ------------------------------------------------------------------------ # SELECT ALL LOADED OBJECTS - bpy.ops.object.select_all(action='DESELECT') + bpy.ops.object.select_all(action='DESELECT') obj = None for obj in atom_object_list: obj.select = True @@ -1139,7 +1119,7 @@ def DEF_atom_pdb_main(use_mesh,Ball_azimuth,Ball_zenith, if obj: bpy.context.scene.objects.active = obj - print("\n\nAll atoms (%d) and sticks (%d) have been drawn - finished.\n\n" + print("\n\nAll atoms (%d) and sticks (%d) have been drawn - finished.\n\n" % (Number_of_total_atoms,Number_of_sticks)) |