Skip to content
Snippets Groups Projects
__init__.py 29 KiB
Newer Older
  • Learn to ignore specific revisions
  • Campbell Barton's avatar
    Campbell Barton committed
    # ##### 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 #####
    
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    #
    #
    #  Authors           : Clemens Barth (Blendphys@root-1.de), ...
    #
    #  Homepage(Wiki)    : http://development.root-1.de/Atomic_Blender.php
    #  Tracker           : http://projects.blender.org/tracker/index.php?func=detail&aid=29226&group_id=153&atid=467
    #
    #  Start of project              : 2011-08-31 by Clemens Barth
    #  First publication in Blender  : 2011-11-11
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    #  Last modified                 : 2012-10-14
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    #
    #  Acknowledgements: Thanks to ideasman, meta_androcto, truman, kilon,
    #  dairin0d, PKHG, Valter, etc
    #
    
    
    Campbell Barton's avatar
    Campbell Barton committed
    bl_info = {
        "name": "PDB Atomic Blender",
        "description": "Loading and manipulating atoms from PDB files",
        "author": "Clemens Barth",
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        "version": (1,3),
    
    Campbell Barton's avatar
    Campbell Barton committed
        "blender": (2,6),
        "location": "File -> Import -> PDB (.pdb), Panel: View 3D - Tools",
        "warning": "",
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/"
                    "Py/Scripts/Import-Export/PDB",
    
    Campbell Barton's avatar
    Campbell Barton committed
        "tracker_url": "http://projects.blender.org/tracker/"
    
                       "index.php?func=detail&aid=29226",
    
    Campbell Barton's avatar
    Campbell Barton committed
        "category": "Import-Export"
    }
    
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    import os
    import io
    
    Campbell Barton's avatar
    Campbell Barton committed
    import bpy
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    import bmesh
    
    from bpy.types import Operator, Panel
    
    from bpy_extras.io_utils import ImportHelper, ExportHelper
    
    Campbell Barton's avatar
    Campbell Barton committed
    from bpy.props import (StringProperty,
                           BoolProperty,
                           EnumProperty,
                           IntProperty,
                           FloatProperty)
    
    from . import import_pdb
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    ATOM_PDB_ERROR = ""
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    ATOM_PDB_PANEL = ""
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    
    
    Campbell Barton's avatar
    Campbell Barton committed
    # -----------------------------------------------------------------------------
    #                                                                           GUI
    
    # The panel, which is loaded after the file has been
    # chosen via the menu 'File -> Import'
    
    class CLASS_atom_pdb_panel(Panel):
    
    Campbell Barton's avatar
    Campbell Barton committed
        bl_label       = "PDB - Atomic Blender"
        bl_space_type  = "VIEW_3D"
        bl_region_type = "TOOL_PROPS"
    
        @classmethod
        def poll(self, context):
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            global ATOM_PDB_PANEL
            
            if ATOM_PDB_PANEL == "0" and import_pdb.ATOM_PDB_FILEPATH == "":
    
    Campbell Barton's avatar
    Campbell Barton committed
                return False
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            if ATOM_PDB_PANEL == "0" and import_pdb.ATOM_PDB_FILEPATH != "":
                return True
            if ATOM_PDB_PANEL == "1":
    
    Campbell Barton's avatar
    Campbell Barton committed
                return True
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            if ATOM_PDB_PANEL == "2":
                return False
            
            return True
    
    Campbell Barton's avatar
    Campbell Barton committed
    
        def draw(self, context):
            layout = self.layout
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    
            # This is for the case that a blend file is loaded. 
            if len(context.scene.atom_pdb) == 0:
                bpy.context.scene.atom_pdb.add()
    
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            scn    = context.scene.atom_pdb[0]
    
    Campbell Barton's avatar
    Campbell Barton committed
    
            row = layout.row()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.label(text="Outputs and custom data file")
            box = layout.box()
            row = box.row()
    
    Campbell Barton's avatar
    Campbell Barton committed
            row.label(text="Custom data file")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
    
    Campbell Barton's avatar
    Campbell Barton committed
            col = row.column()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(scn, "datafile")
    
    Campbell Barton's avatar
    Campbell Barton committed
            col.operator("atom_pdb.datafile_apply")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
    
    Campbell Barton's avatar
    Campbell Barton committed
            col = row.column(align=True)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(scn, "PDB_file")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.label(text="Reload structure")
            box = layout.box()
            row = box.row()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col = row.column()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(scn, "use_mesh")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col = row.column()
            col.label(text="Scaling factors")
            row = box.row()
            col = row.column(align=True)  
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.active = scn.use_mesh   
            col.prop(scn, "mesh_azimuth")
            col.prop(scn, "mesh_zenith")
    
            col = row.column(align=True)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(scn, "scale_ballradius")
            col.prop(scn, "scale_distances")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col = row.column()  
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(scn, "use_sticks")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()        
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.active = scn.use_sticks
    
    Campbell Barton's avatar
    Campbell Barton committed
            col = row.column(align=True)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(scn, "sticks_sectors")
            col.prop(scn, "sticks_radius")
            col.prop(scn, "sticks_unit_length")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col = row.column(align=True)        
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(scn, "use_sticks_color")        
            col.prop(scn, "use_sticks_smooth")
            col.prop(scn, "use_sticks_bonds")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()        
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.active = scn.use_sticks
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col = row.column(align=True)
            col = row.column(align=True)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.active = scn.use_sticks and scn.use_sticks_bonds 
            col.prop(scn, "sticks_dist")        
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.prop(scn, "use_center")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
    
    Campbell Barton's avatar
    Campbell Barton committed
            col = row.column()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(scn, "use_camera")
            col.prop(scn, "use_lamp")
    
    Campbell Barton's avatar
    Campbell Barton committed
            col.operator("atom_pdb.button_reload")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(scn, "number_atoms")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
            row.operator("atom_pdb.button_distance")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.prop(scn, "distance")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.label(text="Modify atom radii")
            box = layout.box()
            row = box.row()
    
    Campbell Barton's avatar
    Campbell Barton committed
            row.label(text="All changes concern:")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.prop(scn, "radius_how")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
    
            row.label(text="1. Change type of radii")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.prop(scn, "radius_type")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
    
            row.label(text="2. Change atom radii in pm")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.prop(scn, "radius_pm_name")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.prop(scn, "radius_pm")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
    
            row.label(text="3. Change atom radii by scale")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(scn, "radius_all")
    
            col = row.column(align=True)
    
    Campbell Barton's avatar
    Campbell Barton committed
            col.operator( "atom_pdb.radius_all_bigger" )
            col.operator( "atom_pdb.radius_all_smaller" )
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = box.row()
            row.label(text="4. Show sticks only")
            row = box.row()
            col = row.column()
            col.operator( "atom_pdb.radius_sticks" )
    
    Campbell Barton's avatar
    Campbell Barton committed
            if bpy.context.mode == 'EDIT_MESH':
                row = layout.row()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                row.label(text="Separate atom")
                box = layout.box()
                row = box.row()
    
    Campbell Barton's avatar
    Campbell Barton committed
                row.operator( "atom_pdb.separate_atom" )
    
    
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    # The properties (gadgets) in the panel. They all go to scene
    # during initialization (see end) 
    class CLASS_atom_pdb_Properties(bpy.types.PropertyGroup):
    
    Campbell Barton's avatar
    Campbell Barton committed
        def Callback_radius_type(self, context):
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            scn = bpy.context.scene.atom_pdb[0]
    
    Campbell Barton's avatar
    Campbell Barton committed
            import_pdb.DEF_atom_pdb_radius_type(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                    scn.radius_type,
                    scn.radius_how,)
    
    Campbell Barton's avatar
    Campbell Barton committed
        def Callback_radius_pm(self, context):
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            scn = bpy.context.scene.atom_pdb[0]
    
    Campbell Barton's avatar
    Campbell Barton committed
            import_pdb.DEF_atom_pdb_radius_pm(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                    scn.radius_pm_name,
                    scn.radius_pm,
                    scn.radius_how,)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        # In the file dialog window - Import
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        use_camera = BoolProperty(
    
            name="Camera", default=False,
            description="Do you need a camera?")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        use_lamp = BoolProperty(
    
            name="Lamp", default=False,
            description = "Do you need a lamp?")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        use_mesh = BoolProperty(
    
            name = "Mesh balls", default=False,
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            description = "Use mesh balls instead of NURBS")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        mesh_azimuth = IntProperty(
            name = "Azimuth", default=32, min=1,
    
    Campbell Barton's avatar
    Campbell Barton committed
            description = "Number of sectors (azimuth)")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        mesh_zenith = IntProperty(
            name = "Zenith", default=32, min=1,
    
    Campbell Barton's avatar
    Campbell Barton committed
            description = "Number of sectors (zenith)")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        scale_ballradius = FloatProperty(
            name = "Balls", default=1.0, min=0.0001,
    
    Campbell Barton's avatar
    Campbell Barton committed
            description = "Scale factor for all atom radii")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        scale_distances = FloatProperty (
            name = "Distances", default=1.0, min=0.0001,
    
    Campbell Barton's avatar
    Campbell Barton committed
            description = "Scale factor for all distances")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        use_center = BoolProperty(
    
            name = "Object to origin", default=True,
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            description = "Put the object into the global origin")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        use_sticks = BoolProperty(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            name="Use sticks", default=True,
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            description="Do you want to display the sticks?")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        sticks_sectors = IntProperty(
            name = "Sector", default=20, min=1,
    
            description="Number of sectors of a stick")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        sticks_radius = FloatProperty(
            name = "Radius", default=0.1, min=0.0001,
    
            description ="Radius of a stick")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        sticks_unit_length = FloatProperty(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            name = "Unit", default=0.05, min=0.0001,
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            description = "Length of the unit of a stick in Angstrom")        
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        use_sticks_color = BoolProperty(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            name="Color", default=True,
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            description="The sticks appear in the color of the atoms")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        use_sticks_smooth = BoolProperty(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            name="Smooth", default=False,
            description="The sticks are round (sectors are not visible)")     
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        use_sticks_bonds = BoolProperty(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            name="Bonds", default=False,
    
            description="Show double and tripple bonds.")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        sticks_dist = FloatProperty(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            name="Distance", default = 1.1, min=1.0, max=3.0,
            description="Distance between sticks measured in stick diameter")        
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        atomradius = EnumProperty(
    
    Campbell Barton's avatar
    Campbell Barton committed
            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")),
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                   default='0',)  
    
    Campbell Barton's avatar
    Campbell Barton committed
        # In the panel
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        datafile = StringProperty(
    
            name = "", description="Path to your custom data file",
    
    Campbell Barton's avatar
    Campbell Barton committed
            maxlen = 256, default = "", subtype='FILE_PATH')
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        PDB_file = StringProperty(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            name = "PDB file", default="",
    
            description = "Path of the PDB file")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        number_atoms = StringProperty(name="",
    
    Campbell Barton's avatar
    Campbell Barton committed
            default="Number", description = "This output shows "
            "the number of atoms which have been loaded")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        distance = StringProperty(
    
            name="", default="Distance (A)",
            description="Distance of 2 objects in Angstrom")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        radius_how = EnumProperty(
    
    Campbell Barton's avatar
    Campbell Barton committed
            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',)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        radius_type = EnumProperty(
    
    Campbell Barton's avatar
    Campbell Barton committed
            name="Type",
            description="Which type of atom radii?",
            items=(('0',"predefined", "Use pre-defined radii"),
    
                   ('1',"atomic", "Use atomic radii"),
    
    Campbell Barton's avatar
    Campbell Barton committed
                   ('2',"van der Waals","Use van der Waals radii")),
    
                   default='0',update=Callback_radius_type)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        radius_pm_name = StringProperty(
    
            name="", default="Atom name",
    
    Campbell Barton's avatar
    Campbell Barton committed
            description="Put in the name of the atom (e.g. Hydrogen)")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        radius_pm = FloatProperty(
            name="", default=100.0, min=0.01,
    
            description="Put in the radius of the atom (in pm)",
    
    Campbell Barton's avatar
    Campbell Barton committed
            update=Callback_radius_pm)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        radius_all = FloatProperty(
            name="Scale", default = 1.05, min=1.0, max=5.0,
    
    Campbell Barton's avatar
    Campbell Barton committed
            description="Put in the scale factor")
    
    Campbell Barton's avatar
    Campbell Barton committed
    # Button loading a custom data file
    
    class CLASS_atom_pdb_datafile_apply(Operator):
    
    Campbell Barton's avatar
    Campbell Barton committed
        bl_idname = "atom_pdb.datafile_apply"
        bl_label = "Apply"
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        bl_description = "Use color and radii values stored in the custom file"
    
    Campbell Barton's avatar
    Campbell Barton committed
    
        def execute(self, context):
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            scn    = bpy.context.scene.atom_pdb[0]
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            if scn.datafile == "":
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            import_pdb.DEF_atom_pdb_custom_datafile(scn.datafile)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    # Button for separating single objects from a atom mesh
    
    class CLASS_atom_pdb_separate_atom(Operator):
    
    Campbell Barton's avatar
    Campbell Barton committed
        bl_idname = "atom_pdb.separate_atom"
        bl_label = "Separate atom"
        bl_description = "Separate the atom you have chosen"
    
        def execute(self, context):
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            scn = bpy.context.scene.atom_pdb[0]
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            # Get first all important properties from the atoms, which the user
    
    Campbell Barton's avatar
    Campbell Barton committed
            # has chosen: location, color, scale
            obj = bpy.context.edit_object
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            bm = bmesh.from_edit_mesh(obj.data)
    
            locations = []
    
            for v in bm.verts:
                if v.select:
                    locations.append(obj.matrix_world * v.co)
    
            bm.free()
            del(bm)
    
            name  = obj.name
    
    Campbell Barton's avatar
    Campbell Barton committed
            scale = obj.children[0].scale
    
            material = obj.children[0].active_material
    
    
    Campbell Barton's avatar
    Campbell Barton committed
            # Separate the vertex from the main mesh and create a new mesh.
            bpy.ops.mesh.separate()
            new_object = bpy.context.scene.objects[0]
            # And now, switch to the OBJECT mode such that we can ...
    
            bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
    
    Campbell Barton's avatar
    Campbell Barton committed
            # ... delete the new mesh including the separated vertex
    
            bpy.ops.object.select_all(action='DESELECT')
    
    Campbell Barton's avatar
    Campbell Barton committed
            new_object.select = True
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            bpy.ops.object.delete()  
    
    Campbell Barton's avatar
    Campbell Barton committed
    
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            # Create new atoms/vacancies at the position of the old atoms
    
            current_layers=bpy.context.scene.layers
    
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            # For all selected positions do:
            for location in locations:
                if "Vacancy" not in name:
                    if scn.use_mesh == False:
                        bpy.ops.surface.primitive_nurbs_surface_sphere_add(
    
                                        view_align=False, enter_editmode=False,
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                                        location=location,
    
                                        rotation=(0.0, 0.0, 0.0),
                                        layers=current_layers)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                    else:
                        bpy.ops.mesh.primitive_uv_sphere_add(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                                    segments=scn.mesh_azimuth,
                                    ring_count=scn.mesh_zenith,
    
                                    size=1, view_align=False, enter_editmode=False,
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                                    location=location,
    
                                    rotation=(0, 0, 0),
                                    layers=current_layers)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                else:
                    bpy.ops.mesh.primitive_cube_add(
    
                                   view_align=False, enter_editmode=False,
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                                   location=location,
    
                                   rotation=(0.0, 0.0, 0.0),
                                   layers=current_layers)
    
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                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"
                new_atom.select = False
    
    
    Campbell Barton's avatar
    Campbell Barton committed
            bpy.context.scene.objects.active = obj
    
            bpy.ops.object.select_all(action='DESELECT')
    
    
    Campbell Barton's avatar
    Campbell Barton committed
            return {'FINISHED'}
    
    
    # Button for measuring the distance of the active objects
    
    class CLASS_atom_pdb_distance_button(Operator):
    
    Campbell Barton's avatar
    Campbell Barton committed
        bl_idname = "atom_pdb.button_distance"
        bl_label = "Measure ..."
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        bl_description = "Measure the distance between two objects (only in Object Mode)"
    
    Campbell Barton's avatar
    Campbell Barton committed
    
        def execute(self, context):
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            scn    = bpy.context.scene.atom_pdb[0]
    
    Campbell Barton's avatar
    Campbell Barton committed
            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
    
    Campbell Barton's avatar
    Campbell Barton committed
               pos    = str.find(dist, ".")
    
               dist   = dist[:pos+4]
    
    Campbell Barton's avatar
    Campbell Barton committed
               dist   = dist + " A"
    
            # Put the distance into the string of the output field.
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            scn.distance = dist
    
    Campbell Barton's avatar
    Campbell Barton committed
            return {'FINISHED'}
    
    
    # Button for increasing the radii of all atoms
    
    class CLASS_atom_pdb_radius_all_bigger_button(Operator):
    
    Campbell Barton's avatar
    Campbell Barton committed
        bl_idname = "atom_pdb.radius_all_bigger"
        bl_label = "Bigger ..."
        bl_description = "Increase the radii of the atoms"
    
        def execute(self, context):
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            scn = bpy.context.scene.atom_pdb[0]
    
    Campbell Barton's avatar
    Campbell Barton committed
            import_pdb.DEF_atom_pdb_radius_all(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                    scn.radius_all,
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                    scn.radius_how,)
    
    Campbell Barton's avatar
    Campbell Barton committed
            return {'FINISHED'}
    
    
    # Button for decreasing the radii of all atoms
    
    class CLASS_atom_pdb_radius_all_smaller_button(Operator):
    
    Campbell Barton's avatar
    Campbell Barton committed
        bl_idname = "atom_pdb.radius_all_smaller"
        bl_label = "Smaller ..."
        bl_description = "Decrease the radii of the atoms"
    
        def execute(self, context):
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            scn = bpy.context.scene.atom_pdb[0]
    
    Campbell Barton's avatar
    Campbell Barton committed
            import_pdb.DEF_atom_pdb_radius_all(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                    1.0/scn.radius_all,
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                    scn.radius_how,)
    
    Campbell Barton's avatar
    Campbell Barton committed
            return {'FINISHED'}
    
    
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    # Button for showing the sticks only - the radii of the atoms downscaled onto
    # 90% of the stick radius
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    class CLASS_atom_pdb_radius_sticks_button(Operator):
        bl_idname = "atom_pdb.radius_sticks"
        bl_label = "Show sticks"
        bl_description = "Show only the sticks (atom radii = stick radii)"
    
        def execute(self, context):
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            global ATOM_PDB_ERROR
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            scn = bpy.context.scene.atom_pdb[0]
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                    
            result = import_pdb.DEF_atom_pdb_radius_sticks(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                         0.01,
                         scn.radius_how,)  
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            if result == False:
                ATOM_PDB_ERROR = "No sticks => no changes"
                bpy.ops.atom_pdb.error_dialog('INVOKE_DEFAULT')
                                              
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            return {'FINISHED'}
    
    
    # The button for reloading the atoms and creating the scene
    
    class CLASS_atom_pdb_load_button(Operator):
    
    Campbell Barton's avatar
    Campbell Barton committed
        bl_idname = "atom_pdb.button_reload"
        bl_label = "RELOAD"
        bl_description = "Load the structure again"
    
    Campbell Barton's avatar
    Campbell Barton committed
        def execute(self, context):
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            scn = context.scene.atom_pdb[0]
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            
    
    Campbell Barton's avatar
    Campbell Barton committed
            atom_number = import_pdb.DEF_atom_pdb_main(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                          scn.use_mesh,
                          scn.mesh_azimuth,
                          scn.mesh_zenith,
                          scn.scale_ballradius,
                          scn.atomradius,
                          scn.scale_distances,
                          scn.use_sticks,
                          scn.use_sticks_color,
                          scn.use_sticks_smooth,
                          scn.use_sticks_bonds,
                          scn.sticks_unit_length,
                          scn.sticks_dist,
                          scn.sticks_sectors,
                          scn.sticks_radius,
                          scn.use_center,
                          scn.use_camera,
                          scn.use_lamp,
                          scn.datafile)     
                          
            scn.number_atoms = str(atom_number) + " atoms"
    
    Campbell Barton's avatar
    Campbell Barton committed
    
            return {'FINISHED'}
    
    
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    def DEF_panel_yes_no():
        global ATOM_PDB_PANEL
    
        datafile_path = bpy.utils.user_resource('SCRIPTS', path='', create=False)
        if os.path.isdir(datafile_path) == False:
            bpy.utils.user_resource('SCRIPTS', path='', create=True)
        datafile_path = os.path.join(datafile_path, "presets")
        if os.path.isdir(datafile_path) == False:
            os.mkdir(datafile_path)   
        datafile = os.path.join(datafile_path, "io_mesh_pdb.pref")
        if os.path.isfile(datafile):
            datafile_fp = io.open(datafile, "r")
            for line in datafile_fp:
                if "Panel" in line:
                    ATOM_PDB_PANEL = line[-2:]
                    ATOM_PDB_PANEL = ATOM_PDB_PANEL[0:1]
                    bpy.context.scene.use_panel = ATOM_PDB_PANEL
                    break       
            datafile_fp.close()
        else:
            DEF_panel_write_pref("0") 
    
    
    def DEF_panel_write_pref(value): 
        datafile_path = bpy.utils.user_resource('SCRIPTS', path='', create=False)
        datafile_path = os.path.join(datafile_path, "presets")
        datafile = os.path.join(datafile_path, "io_mesh_pdb.pref")
        datafile_fp = io.open(datafile, "w")
        datafile_fp.write("Atomic Blender PDB - Import/Export - Preferences\n")
        datafile_fp.write("================================================\n")
        datafile_fp.write("\n")
        datafile_fp.write("Panel: "+value+"\n\n\n")
        datafile_fp.close()        
    
    
    class CLASS_atom_pdb_error_dialog(bpy.types.Operator):
        bl_idname = "atom_pdb.error_dialog"
        bl_label = "Attention !"
        
        def draw(self, context):
            layout = self.layout
            row = layout.row()
            row.label(text="                          "+ATOM_PDB_ERROR) 
        def execute(self, context):
            print("Atomic Blender - Error: "+ATOM_PDB_ERROR+"\n")
            return {'FINISHED'}
        def invoke(self, context, event):
            return context.window_manager.invoke_props_dialog(self)        
    
    
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    # This is the class for the file dialog of the importer.
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    class CLASS_ImportPDB(Operator, ImportHelper):
    
        bl_idname = "import_mesh.pdb"
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        bl_label  = "Import Protein Data Bank(*.pdb)"
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        bl_options = {'PRESET', 'UNDO'}
    
    Campbell Barton's avatar
    Campbell Barton committed
        filename_ext = ".pdb"
        filter_glob  = StringProperty(default="*.pdb", options={'HIDDEN'},)
    
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        bpy.types.Scene.use_panel = EnumProperty(
            name="Panel",
            description="Choose whether the panel shall appear or not in the View 3D.",
            items=(('0', "Once", "The panel appears only in this session"),
                   ('1', "Always", "The panel always appears when Blender is started"),
                   ('2', "Never", "The panel never appears")),
                   default='0')  
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        use_camera = BoolProperty(
            name="Camera", default=False,
            description="Do you need a camera?")
        use_lamp = BoolProperty(
            name="Lamp", default=False,
            description = "Do you need a lamp?")
        use_mesh = BoolProperty(
            name = "Mesh balls", default=False,
            description = "Use mesh balls instead of NURBS")
        mesh_azimuth = IntProperty(
            name = "Azimuth", default=32, min=1,
            description = "Number of sectors (azimuth)")
        mesh_zenith = IntProperty(
            name = "Zenith", default=32, min=1,
            description = "Number of sectors (zenith)")
        scale_ballradius = FloatProperty(
            name = "Balls", default=1.0, min=0.0001,
            description = "Scale factor for all atom radii")
        scale_distances = FloatProperty (
            name = "Distances", default=1.0, min=0.0001,
            description = "Scale factor for all distances")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        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',)        
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        use_sticks = BoolProperty(
            name="Use sticks", default=True,
            description="Do you want to display the sticks?")
        sticks_sectors = IntProperty(
            name = "Sector", default=20, min=1,
            description="Number of sectors of a stick")
        sticks_radius = FloatProperty(
            name = "Radius", default=0.1, min=0.0001,
            description ="Radius of a stick")
        sticks_unit_length = FloatProperty(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            name = "Unit", default=0.05, min=0.0001,
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            description = "Length of the unit of a stick in Angstrom")        
        use_sticks_color = BoolProperty(
            name="Color", default=True,
            description="The sticks appear in the color of the atoms")
        use_sticks_smooth = BoolProperty(
            name="Smooth", default=False,
            description="The sticks are round (sectors are not visible)")     
        use_sticks_bonds = BoolProperty(
            name="Bonds", default=False,
            description="Show double and tripple bonds.")
        sticks_dist = FloatProperty(
            name="Distance", default = 1.1, min=1.0, max=3.0,
            description="Distance between sticks measured in stick diameter")        
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        use_center = BoolProperty(
            name = "Object to origin", default=True,
            description = "Put the object into the global origin")           
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        datafile = StringProperty(
            name = "", description="Path to your custom data file",
            maxlen = 256, default = "", subtype='FILE_PATH')
    
    
    Campbell Barton's avatar
    Campbell Barton committed
        def draw(self, context):
    
            layout = self.layout
    
    Campbell Barton's avatar
    Campbell Barton committed
            row = layout.row()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.prop(self, "use_camera")
            row.prop(self, "use_lamp")
    
            row = layout.row()
            col = row.column()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(self, "use_mesh")
    
            col = row.column(align=True)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.active = self.use_mesh
            col.prop(self, "mesh_azimuth")
            col.prop(self, "mesh_zenith")
    
            row = layout.row()
            col = row.column()
    
    Campbell Barton's avatar
    Campbell Barton committed
            col.label(text="Scaling factors")
            col = row.column(align=True)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(self, "scale_ballradius")
            col.prop(self, "scale_distances")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.prop(self, "atomradius")
            row = layout.row()
    
    Campbell Barton's avatar
    Campbell Barton committed
            col = row.column()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(self, "use_sticks")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = layout.row()        
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.active = self.use_sticks
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col = row.column()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(self, "sticks_sectors")
            col.prop(self, "sticks_radius")
            col.prop(self, "sticks_unit_length")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col = row.column(align=True)        
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.prop(self, "use_sticks_color")        
            col.prop(self, "use_sticks_smooth")
            col.prop(self, "use_sticks_bonds")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = layout.row()        
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.active = self.use_sticks
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col = row.column(align=True)
            col = row.column(align=True)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            col.active = self.use_sticks and self.use_sticks_bonds 
            col.prop(self, "sticks_dist")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.prop(self, "use_center")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.prop(bpy.context.scene, "use_panel")
    
    Campbell Barton's avatar
    Campbell Barton committed
    
    
        def execute(self, context):
    
    Campbell Barton's avatar
    Campbell Barton committed
            # This is in order to solve this strange 'relative path' thing.
            import_pdb.ATOM_PDB_FILEPATH = bpy.path.abspath(self.filepath)
    
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            # Execute main routine                
    
    Campbell Barton's avatar
    Campbell Barton committed
            atom_number = import_pdb.DEF_atom_pdb_main(
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                          self.use_mesh,
                          self.mesh_azimuth,
                          self.mesh_zenith,
                          self.scale_ballradius,
                          self.atomradius,
                          self.scale_distances,
                          self.use_sticks,
                          self.use_sticks_color,
                          self.use_sticks_smooth,
                          self.use_sticks_bonds,
                          self.sticks_unit_length,
                          self.sticks_dist,
                          self.sticks_sectors,
                          self.sticks_radius,
                          self.use_center,
                          self.use_camera,
                          self.use_lamp,
                          self.datafile)        
    
            # Copy the whole bunch of values into the property collection.
            scn = context.scene.atom_pdb[0]
            scn.use_mesh = self.use_mesh
            scn.mesh_azimuth = self.mesh_azimuth
            scn.mesh_zenith = self.mesh_zenith
            scn.scale_ballradius = self.scale_ballradius
            scn.atomradius = self.atomradius
            scn.scale_distances = self.scale_distances
            scn.use_sticks = self.use_sticks
            scn.use_sticks_color = self.use_sticks_color
            scn.use_sticks_smooth = self.use_sticks_smooth
            scn.use_sticks_bonds = self.use_sticks_bonds
            scn.sticks_unit_length = self.sticks_unit_length
            scn.sticks_dist = self.sticks_dist
            scn.sticks_sectors = self.sticks_sectors
            scn.sticks_radius = self.sticks_radius
            scn.use_center = self.use_center
            scn.use_camera = self.use_camera
            scn.use_lamp = self.use_lamp
            scn.datafile = self.datafile
            
            scn.number_atoms = str(atom_number) + " atoms"
            scn.PDB_file = import_pdb.ATOM_PDB_FILEPATH
    
    Clemens Barth's avatar
     
    Clemens Barth committed
          
            global ATOM_PDB_PANEL
            ATOM_PDB_PANEL = bpy.context.scene.use_panel
            DEF_panel_write_pref(bpy.context.scene.use_panel)
    
    Campbell Barton's avatar
    Campbell Barton committed
    
            return {'FINISHED'}
    
    
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    # This is the class for the file dialog of the exporter.
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    class CLASS_ExportPDB(Operator, ExportHelper):
    
        bl_idname = "export_mesh.pdb"
        bl_label  = "Export Protein Data Bank(*.pdb)"
        filename_ext = ".pdb"
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    
        filter_glob  = StringProperty(
            default="*.pdb", options={'HIDDEN'},)
    
        atom_pdb_export_type = EnumProperty(
            name="Type of Objects",
            description="Choose type of objects",
            items=(('0', "All", "Export all active objects"),
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                   ('1', "Elements", "Export only those active objects which have"
                                     " a proper element name")),
    
    Clemens Barth's avatar
     
    Clemens Barth committed
                   default='1',) 
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row = layout.row()
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            row.prop(self, "atom_pdb_export_type")
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    
    
        def execute(self, context):
            # This is in order to solve this strange 'relative path' thing.
            export_pdb.ATOM_PDB_FILEPATH = bpy.path.abspath(self.filepath)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
            export_pdb.DEF_atom_pdb_export(self.atom_pdb_export_type)
    
    Campbell Barton's avatar
    Campbell Barton committed
    # The entry into the menu 'file -> import'
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    def DEF_menu_func_import(self, context):
        self.layout.operator(CLASS_ImportPDB.bl_idname, text="Protein Data Bank (.pdb)")
    
    Campbell Barton's avatar
    Campbell Barton committed
    
    
    # The entry into the menu 'file -> export'
    
    Clemens Barth's avatar
     
    Clemens Barth committed
    def DEF_menu_func_export(self, context):
        self.layout.operator(CLASS_ExportPDB.bl_idname, text="Protein Data Bank (.pdb)")
    
    Campbell Barton's avatar
    Campbell Barton committed
    
    def register():
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        DEF_panel_yes_no()
    
    Campbell Barton's avatar
    Campbell Barton committed
        bpy.utils.register_module(__name__)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        bpy.types.INFO_MT_file_import.append(DEF_menu_func_import)
        bpy.types.INFO_MT_file_export.append(DEF_menu_func_export)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        bpy.types.Scene.atom_pdb = bpy.props.CollectionProperty(type=CLASS_atom_pdb_Properties)    
        bpy.context.scene.atom_pdb.add()
        
    
    Campbell Barton's avatar
    Campbell Barton committed
    def unregister():
    
        bpy.utils.unregister_module(__name__)
    
    Clemens Barth's avatar
     
    Clemens Barth committed
        bpy.types.INFO_MT_file_import.remove(DEF_menu_func_import)
        bpy.types.INFO_MT_file_export.remove(DEF_menu_func_export)
    
    Campbell Barton's avatar
    Campbell Barton committed
    if __name__ == "__main__":
    
    Campbell Barton's avatar
    Campbell Barton committed
        register()