Dear all.
[blender-addons-contrib.git] / io_mesh_xyz / __init__.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 bl_info = {
20     "name": "XYZ Atomic Blender",
21     "description": "Loading and manipulating atoms from XYZ files",
22     "author": "Clemens Barth",
23     "version": (0,5),
24     "blender": (2,6),
25     "api": 31236,
26     "location": "File -> Import -> XYZ (.xyz), Panel: View 3D - Tools",
27     "warning": "",
28     "wiki_url": "http://development.root-1.de/Atomic_Blender.php",
29     "tracker_url": "http://projects.blender.org/tracker/"
30                    "index.php?func=detail&aid=29646&group_id=153&atid=468",
31     "category": "Import-Export"
32 }
33
34
35 import bpy
36 from bpy.types import Operator, Panel
37 from bpy_extras.io_utils import ImportHelper
38 from bpy.props import (StringProperty,
39                        BoolProperty,
40                        EnumProperty,
41                        IntProperty,
42                        FloatProperty)
43
44
45
46 from . import import_xyz
47 ATOM_XYZ_ERROR = ""
48
49 # -----------------------------------------------------------------------------
50 #                                                                           GUI
51
52 # This is the panel, which can be used to prepare the scene.
53 # It is loaded after the file has been chosen via the menu 'File -> Import'
54 class CLASS_atom_xyz_prepare_panel(Panel):
55     bl_label       = "XYZ - Atomic Blender"
56     #bl_space_type  = "PROPERTIES"
57     #bl_region_type = "WINDOW"
58     #bl_context     = "physics"
59     # This could be also an option ... :
60     bl_space_type  = "VIEW_3D"
61     bl_region_type = "TOOL_PROPS"
62
63     @classmethod
64     def poll(self, context):
65         if import_xyz.ATOM_XYZ_FILEPATH == "":
66             return False
67         else:
68             return True
69
70     def draw(self, context):
71         layout = self.layout
72         scn    = bpy.context.scene
73
74         row = layout.row()
75         row.label(text="Outputs and custom data file")
76
77         box = layout.box()
78         row = box.row()
79         row.label(text="Custom data file")
80         row = box.row()
81         col = row.column()
82         col.prop(scn, "atom_xyz_datafile")
83         col.operator("atom_xyz.datafile_apply")
84         row = box.row()
85         col = row.column(align=True)
86         col.prop(scn, "atom_xyz_XYZ_file")
87         row = box.row()
88         # TODO, use lanel() instead
89         row.prop(scn, "atom_xyz_number_atoms")
90         row = box.row()
91         row.operator("atom_xyz.button_distance")
92         row.prop(scn, "atom_xyz_distance")
93
94         row = layout.row()
95         row.label(text="Choice of atom radii")
96         box = layout.box()
97
98         row = box.row()
99         row.label(text="All changes concern:")
100         row = box.row()
101         row.prop(scn, "atom_xyz_radius_how")
102
103         row = box.row()
104         row.label(text="1. Change type of radii")
105         row = box.row()
106         row.prop(scn, "atom_xyz_radius_type")
107
108         row = box.row()
109         row.label(text="2. Change atom radii in pm")
110         row = box.row()
111         row.prop(scn, "atom_xyz_radius_pm_name")
112         row = box.row()
113         row.prop(scn, "atom_xyz_radius_pm")
114
115         row = box.row()
116         row.label(text="3. Change atom radii by scale")
117         row = box.row()
118         col = row.column()
119         col.prop(scn, "atom_xyz_radius_all")
120         col = row.column(align=True)
121         col.operator( "atom_xyz.radius_all_bigger" )
122         col.operator( "atom_xyz.radius_all_smaller" )
123
124         if bpy.context.mode == 'EDIT_MESH':
125
126             layout.separator()
127             row = box.row()
128             row.operator( "atom_xyz.separate_atom" )
129
130         row = layout.row()
131         row.label(text="Loading frames")
132
133         box = layout.box()
134         row = box.row()
135         col = row.column()
136         col.label(text="Frames")
137         col = row.column()
138         col.prop(scn, "atom_xyz_number_frames")
139         row = box.row()
140         col = row.column()
141         col.label(text="Skip frames")
142         col = row.column()
143         col.prop(scn, "atom_xyz_skip_frames")
144         row = box.row()
145         col = row.column()
146         col.label(text="Frames/key")
147         col = row.column()
148         col.prop(scn, "atom_xyz_images_per_key")        
149         
150         row = box.row()
151         row.operator("atom_xyz.load_frames")
152         row = box.row()
153         row.operator("atom_xyz.delete_keys")
154         row = box.row()
155         row.operator( "atom_xyz.create_command")
156         row = box.row()
157         row.operator( "atom_xyz.render")
158
159
160 class CLASS_atom_xyz_IO(bpy.types.PropertyGroup):
161
162     def Callback_radius_type(self, context):
163         scnn = bpy.context.scene
164         import_xyz.DEF_atom_xyz_radius_type(
165                 scnn.atom_xyz_radius_type,
166                 scnn.atom_xyz_radius_how,
167                 )
168
169     def Callback_radius_pm(self, context):
170         scnn = bpy.context.scene
171         import_xyz.DEF_atom_xyz_radius_pm(
172                 scnn.atom_xyz_radius_pm_name,
173                 scnn.atom_xyz_radius_pm,
174                 scnn.atom_xyz_radius_how,
175                 )
176
177     # In the file dialog window
178     scn = bpy.types.Scene
179     scn.use_atom_xyz_cam = BoolProperty(
180         name="Camera", default=False,
181         description="Do you need a camera?")
182     scn.use_atom_xyz_lamp = BoolProperty(
183         name="Lamp", default=False,
184         description = "Do you need a lamp?")
185     scn.use_atom_xyz_mesh = BoolProperty(
186         name = "Mesh balls", default=False,
187         description = "Do you want to use mesh balls instead of NURBS?")
188     scn.atom_xyz_mesh_azimuth = IntProperty(
189         name = "Azimuth", default=32, min=0,
190         description = "Number of sectors (azimuth)")
191     scn.atom_xyz_mesh_zenith = IntProperty(
192         name = "Zenith", default=32, min=0,
193         description = "Number of sectors (zenith)")
194     scn.atom_xyz_scale_ballradius = FloatProperty(
195         name = "Balls", default=1.0, min=0.0,
196         description = "Scale factor for all atom radii")
197     scn.atom_xyz_scale_distances = FloatProperty (
198         name = "Distances", default=1.0, min=0.0,
199         description = "Scale factor for all distances")
200     scn.use_atom_xyz_center = BoolProperty(
201         name = "Object to origin", default=False,
202         description = "Shall the object first put into the global origin "
203         "before applying the offsets on the left?")
204     scn.atom_xyz_atomradius = EnumProperty(
205         name="Type of radius",
206         description="Choose type of atom radius",
207         items=(('0', "Pre-defined", "Use pre-defined radii"),
208                ('1', "Atomic", "Use atomic radii"),
209                ('2', "van der Waals", "Use van der Waals radii")),
210                default='0',)
211
212     # In the panel, first part
213     scn.atom_xyz_datafile = StringProperty(
214         name = "", description="Path to your custom data file",
215         maxlen = 256, default = "", subtype='FILE_PATH')
216     scn.atom_xyz_XYZ_file = StringProperty(
217         name = "Path to file", default="",
218         description = "Path of the XYZ file")
219     # TODO, remove this property, its used for display only!
220     scn.atom_xyz_number_atoms = StringProperty(name="",
221         default="Number", description = "This output shows "
222         "the number of atoms which have been loaded")
223     scn.atom_xyz_distance = StringProperty(
224         name="", default="Distance (A)",
225         description="Distance of 2 objects in Angstrom")
226     scn.atom_xyz_radius_how = EnumProperty(
227         name="",
228         description="Which objects shall be modified?",
229         items=(('ALL_ACTIVE',"all active objects", "in the current layer"),
230                ('ALL_IN_LAYER',"all"," in active layer(s)")),
231                default='ALL_ACTIVE',)
232     scn.atom_xyz_radius_type = EnumProperty(
233         name="Type",
234         description="Which type of atom radii?",
235         items=(('0',"predefined", "Use pre-defined radii"),
236                ('1',"atomic", "Use atomic radii"),
237                ('2',"van der Waals","Use van der Waals radii")),
238                default='0',update=Callback_radius_type)
239     scn.atom_xyz_radius_pm_name = StringProperty(
240         name="", default="Atom name",
241         description="Put in the name of the atom (e.g. Hydrogen)")
242     scn.atom_xyz_radius_pm = FloatProperty(
243         name="", default=100.0, min=0.0,
244         description="Put in the radius of the atom (in pm)",
245         update=Callback_radius_pm)
246     scn.atom_xyz_radius_all = FloatProperty(
247         name="Scale", default = 1.05, min=1.0,
248         description="Put in the scale factor")
249
250
251     # In the panel, second part
252     scn.atom_xyz_number_frames = StringProperty(
253         name="", default="0",
254         description="This is the total number of frames stored in the xyz file")
255     scn.atom_xyz_skip_frames = IntProperty(
256         name="", default=0, min=0,
257         description="Number of frames you want to skip.")
258     scn.atom_xyz_images_per_key = IntProperty(
259         name="", default=1, min=0,
260         description="Choose the number of images between 2 keys.")
261
262
263
264 # Button for creating a file that contains the command for rendering
265 class CLASS_atom_xyz_create_command(Operator):
266     bl_idname = "atom_xyz.create_command"
267     bl_label = "Create command"
268     bl_description = "Create a shell command for rendering the scene"
269
270     def execute(self, context):
271         global ATOM_XYZ_ERROR
272         import os
273  
274         scn = bpy.context.scene
275
276         fstart = scn.frame_start
277         fend = scn.frame_end
278         file_blend = bpy.context.blend_data.filepath
279         
280         if file_blend == "":
281             ATOM_XYZ_ERROR = "Save your scene first !"
282             bpy.ops.atom_xyz.error_dialog('INVOKE_DEFAULT')
283             return {'FINISHED'}
284             
285         cameras = []    
286         FOUND = False    
287         for obj in bpy.context.scene.objects:  
288             if obj.type == "CAMERA":
289                 cameras.append(obj)
290                 FOUND = True   
291         if FOUND == False:
292             ATOM_XYZ_ERROR = "No camera => no images !"
293             bpy.ops.atom_xyz.error_dialog('INVOKE_DEFAULT')
294             return {'FINISHED'}      
295         if bpy.context.scene.camera == None:
296             bpy.context.scene.camera = cameras[0]
297             
298         KEYS_PRESENT = True
299         for element in import_xyz.STRUCTURE:
300             bpy.ops.object.select_all(action='DESELECT')
301             bpy.context.scene.objects.active = element
302             element.select = True
303             if element.data.shape_keys == None:
304                 KEYS_PRESENT = False
305                 break       
306         if KEYS_PRESENT == False:
307             ATOM_XYZ_ERROR = "No frames => no movie !"
308             bpy.ops.atom_xyz.error_dialog('INVOKE_DEFAULT')
309             return {'FINISHED'}     
310         
311         bpy.ops.wm.save_mainfile()
312         
313         file_name = bpy.path.basename(file_blend)
314         file_path = file_blend.replace(file_name,"")
315         file_movie = bpy.path.display_name_from_filepath(file_blend)
316         blender_exe = bpy.app.binary_path
317                 
318         if os.name == "posix":
319             execute = (blender_exe+" -b \'"+file_blend+"\' -x 1 -o //"+file_movie+
320                   "_ -F AVIJPEG -s "+str(fstart)+" -e "+str(scn.frame_end)+" -a")
321         else:
322             execute = ("\""+blender_exe+"\" -b "+file_blend+" -x 1 -o //"+file_movie+
323                   "_ -F AVIJPEG -s "+str(fstart)+" -e "+str(scn.frame_end)+" -a")
324
325         if os.name == "posix":
326             command_file = file_path + file_movie + ".sh"
327         else:
328             command_file = file_path + file_movie + ".txt"
329         command_fp = open(command_file,"w")
330            
331         if os.name == "posix":        
332             command_fp.write("#!/bin/sh\n")   
333         command_fp.write("\n"+execute+"\n")     
334         command_fp.close()
335
336         return {'FINISHED'}
337
338
339 # Button for rendering the scene in a terminal
340 class CLASS_atom_xyz_render(Operator):
341     bl_idname = "atom_xyz.render"
342     bl_label = "Render"
343     bl_description = "Render the scene"
344
345     def execute(self, context):
346         global ATOM_XYZ_ERROR
347         import os
348  
349         scn = bpy.context.scene
350
351         fstart = scn.frame_start
352         fend = scn.frame_end
353         file_blend = bpy.context.blend_data.filepath
354         
355         if file_blend == "":
356             ATOM_XYZ_ERROR = "Save your scene first!"
357             bpy.ops.atom_xyz.error_dialog('INVOKE_DEFAULT')
358             return {'FINISHED'}
359             
360         cameras = []    
361         FOUND = False    
362         for obj in bpy.context.scene.objects:  
363             if obj.type == "CAMERA":
364                 cameras.append(obj)
365                 FOUND = True   
366         if FOUND == False:
367             ATOM_XYZ_ERROR = "No camera => no images !"
368             bpy.ops.atom_xyz.error_dialog('INVOKE_DEFAULT')
369             return {'FINISHED'}      
370         if bpy.context.scene.camera == None:
371             bpy.context.scene.camera = cameras[0]
372             
373             
374         KEYS_PRESENT = True
375         for element in import_xyz.STRUCTURE:
376             bpy.ops.object.select_all(action='DESELECT')
377             bpy.context.scene.objects.active = element
378             element.select = True
379             if element.data.shape_keys == None:
380                 KEYS_PRESENT = False
381                 break       
382         if KEYS_PRESENT == False:
383             ATOM_XYZ_ERROR = "No frames => no movie !"
384             bpy.ops.atom_xyz.error_dialog('INVOKE_DEFAULT')
385             return {'FINISHED'}    
386             
387         bpy.ops.wm.save_mainfile()    
388         
389         file_name = bpy.path.basename(file_blend)
390         file_path = file_blend.replace(file_name,"")
391         file_movie = bpy.path.display_name_from_filepath(file_blend)
392         blender_exe = bpy.app.binary_path
393  
394         if os.name == "posix":
395             execute = (blender_exe+" -b \'"+file_blend+"\' -x 1 -o //"+file_movie+
396                   "_ -F AVIJPEG -s "+str(fstart)+" -e "+str(scn.frame_end)+" -a")
397             os_str = "xterm -e \"" + execute + "\" &"
398         else:
399             execute = ("\""+blender_exe+"\" -b "+file_blend+" -x 1 -o //"+file_movie+
400                   "_ -F AVIJPEG -s "+str(fstart)+" -e "+str(scn.frame_end)+" -a")
401             os_str = "C:\WINDOWS\system32\cmd.exe /C " + execute
402             
403         #print(os_str)    
404         os.system(os_str)    
405         
406         return {'FINISHED'}
407
408
409 # Button deleting all shape keys of the structure
410 class CLASS_atom_xyz_delete_keys(Operator):
411     bl_idname = "atom_xyz.delete_keys"
412     bl_label = "Delete keys"
413     bl_description = "Delete the shape keys"
414
415     def execute(self, context):
416     
417         for element in import_xyz.STRUCTURE:
418         
419             if element.data.shape_keys == None:
420                 break
421         
422             bpy.ops.object.select_all(action='DESELECT')
423             bpy.context.scene.objects.active = element
424             element.select = True
425         
426             for key in element.data.shape_keys.key_blocks:
427             
428                 bpy.ops.object.shape_key_remove()
429         
430
431         return {'FINISHED'}
432
433
434 # Button loading the shape keys
435 class CLASS_atom_xyz_load_frames(Operator):
436     bl_idname = "atom_xyz.load_frames"
437     bl_label = "Load frames"
438     bl_description = "Load the frames"
439
440     def execute(self, context):
441         global ATOM_XYZ_ERROR
442     
443         scn = bpy.context.scene
444         
445         KEYS_PRESENT = False
446         for element in import_xyz.STRUCTURE:
447             bpy.ops.object.select_all(action='DESELECT')
448             bpy.context.scene.objects.active = element
449             element.select = True
450             if element.data.shape_keys != None:
451                 KEYS_PRESENT = True
452                 break
453                 
454         if KEYS_PRESENT == True:
455             ATOM_XYZ_ERROR = "Delete first the keys"
456             bpy.ops.atom_xyz.error_dialog('INVOKE_DEFAULT')
457             return {'FINISHED'}
458         
459         
460         import_xyz.DEF_atom_xyz_build_frames(scn.atom_xyz_images_per_key, scn.atom_xyz_skip_frames)
461
462         return {'FINISHED'}
463
464
465
466 # Button loading a custom data file
467 class CLASS_atom_xyz_datafile_apply(Operator):
468     bl_idname = "atom_xyz.datafile_apply"
469     bl_label = "Apply"
470     bl_description = "Use color and radii values stored in the custom file"
471
472     def execute(self, context):
473     
474         scn = bpy.context.scene
475
476         if scn.atom_xyz_datafile == "":
477             return {'FINISHED'}
478
479         import_xyz.DEF_atom_xyz_custom_datafile(scn.atom_xyz_datafile)
480
481         # TODO, move this into 'import_xyz' and call the function
482         for obj in bpy.context.selected_objects:
483             if len(obj.children) != 0:
484                 child = obj.children[0]
485                 if child.type == "SURFACE" or child.type  == "MESH":
486                     for element in import_xyz.ATOM_XYZ_ELEMENTS:
487                         if element.name in obj.name:
488                             child.scale = (element.radii[0],) * 3
489                             child.active_material.diffuse_color = element.color
490             else:
491                 if obj.type == "SURFACE" or obj.type == "MESH":
492                     for element in import_xyz.ATOM_XYZ_ELEMENTS:
493                         if element.name in obj.name:
494                             obj.scale = (element.radii[0],) * 3
495                             obj.active_material.diffuse_color = element.color
496
497         return {'FINISHED'}
498
499
500 # Button for separating a single atom from a structure
501 class CLASS_atom_xyz_separate_atom(Operator):
502     bl_idname = "atom_xyz.separate_atom"
503     bl_label = "Separate atom"
504     bl_description = "Separate the atom you have chosen"
505
506     def execute(self, context):
507         scn    = bpy.context.scene
508
509         # Get first all important properties from the atom which the user
510         # has chosen: location, color, scale
511         obj = bpy.context.edit_object
512         name = obj.name
513         loc_obj_vec = obj.location
514         scale = obj.children[0].scale
515         material = obj.children[0].active_material
516
517         # Separate the vertex from the main mesh and create a new mesh.
518         bpy.ops.mesh.separate()
519         new_object = bpy.context.scene.objects[0]
520         # Keep in mind the coordinates <= We only need this
521         loc_vec = new_object.data.vertices[0].co
522
523         # And now, switch to the OBJECT mode such that we can ...
524         bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
525         # ... delete the new mesh including the separated vertex
526         bpy.ops.object.select_all(action='DESELECT')
527         new_object.select = True
528         bpy.ops.object.delete()  # TODO, use scene.objects.unlink()
529
530         # Create a new atom/vacancy at the position of the old atom
531         current_layers=bpy.context.scene.layers
532
533         if "Vacancy" not in name:
534             if scn.use_atom_xyz_mesh == False:
535                 bpy.ops.surface.primitive_nurbs_surface_sphere_add(
536                                     view_align=False, enter_editmode=False,
537                                     location=loc_vec+loc_obj_vec,
538                                     rotation=(0.0, 0.0, 0.0),
539                                     layers=current_layers)
540             else:
541                 bpy.ops.mesh.primitive_uv_sphere_add(
542                                 segments=scn.atom_xyz_mesh_azimuth,
543                                 ring_count=scn.atom_xyz_mesh_zenith,
544                                 size=1, view_align=False, enter_editmode=False,
545                                 location=loc_vec+loc_obj_vec,
546                                 rotation=(0, 0, 0),
547                                 layers=current_layers)
548         else:
549             bpy.ops.mesh.primitive_cube_add(
550                                view_align=False, enter_editmode=False,
551                                location=loc_vec+loc_obj_vec,
552                                rotation=(0.0, 0.0, 0.0),
553                                layers=current_layers)
554
555         new_atom = bpy.context.scene.objects.active
556         # Scale, material and name it.
557         new_atom.scale = scale
558         new_atom.active_material = material
559         new_atom.name = name + "_sep"
560
561         # Switch back into the 'Edit mode' because we would like to seprate
562         # other atoms may be (more convinient)
563         new_atom.select = False
564         obj.select = True
565         bpy.context.scene.objects.active = obj
566         bpy.ops.object.select_all(action='DESELECT')
567         bpy.ops.object.mode_set(mode='EDIT', toggle=False)
568
569         return {'FINISHED'}
570
571
572 # Button for measuring the distance of the active objects
573 class CLASS_atom_xyz_distance_button(Operator):
574     bl_idname = "atom_xyz.button_distance"
575     bl_label = "Measure ..."
576     bl_description = "Measure the distance between two objects"
577
578     def execute(self, context):
579         scn    = bpy.context.scene
580         dist   = import_xyz.DEF_atom_xyz_distance()
581
582         if dist != "N.A.":
583            # The string length is cut, 3 digits after the first 3 digits
584            # after the '.'. Append also "Angstrom".
585            # Remember: 1 Angstrom = 10^(-10) m
586            pos    = str.find(dist, ".")
587            dist   = dist[:pos+4]
588            dist   = dist + " A"
589
590         # Put the distance into the string of the output field.
591         scn.atom_xyz_distance = dist
592         return {'FINISHED'}
593
594
595 # Button for increasing the radii of all atoms
596 class CLASS_atom_xyz_radius_all_bigger_button(Operator):
597     bl_idname = "atom_xyz.radius_all_bigger"
598     bl_label = "Bigger ..."
599     bl_description = "Increase the radii of the atoms"
600
601     def execute(self, context):
602         scn = bpy.context.scene
603         import_xyz.DEF_atom_xyz_radius_all(
604                 scn.atom_xyz_radius_all,
605                 scn.atom_xyz_radius_how,
606                 )
607         return {'FINISHED'}
608
609
610 # Button for decreasing the radii of all atoms
611 class CLASS_atom_xyz_radius_all_smaller_button(Operator):
612     bl_idname = "atom_xyz.radius_all_smaller"
613     bl_label = "Smaller ..."
614     bl_description = "Decrease the radii of the atoms"
615
616     def execute(self, context):
617         scn = bpy.context.scene
618         import_xyz.DEF_atom_xyz_radius_all(
619                 1.0/scn.atom_xyz_radius_all,
620                 scn.atom_xyz_radius_how,
621                 )
622         return {'FINISHED'}
623
624
625
626 # This is the class for the file dialog.
627 class ImportXYZ(Operator, ImportHelper):
628     bl_idname = "import_mesh.xyz"
629     bl_label  = "Import XYZ (*.xyz)"
630
631     filename_ext = ".xyz"
632     filter_glob  = StringProperty(default="*.xyz", options={'HIDDEN'},)
633
634     def draw(self, context):
635         layout = self.layout
636         scn = bpy.context.scene
637
638         row = layout.row()
639         row.prop(scn, "use_atom_xyz_cam")
640         row.prop(scn, "use_atom_xyz_lamp")
641         row = layout.row()
642         col = row.column()
643         col.prop(scn, "use_atom_xyz_mesh")
644         col = row.column(align=True)
645         col.prop(scn, "atom_xyz_mesh_azimuth")
646         col.prop(scn, "atom_xyz_mesh_zenith")
647
648         row = layout.row()
649         col = row.column()
650         col.label(text="Scaling factors")
651         col = row.column(align=True)
652         col.prop(scn, "atom_xyz_scale_ballradius")
653         col.prop(scn, "atom_xyz_scale_distances")
654
655         row = layout.row()
656         row.prop(scn, "use_atom_xyz_center")
657
658         row = layout.row()
659         row.prop(scn, "atom_xyz_atomradius")
660
661     def execute(self, context):
662         scn = bpy.context.scene
663         
664         import_xyz.ALL_FRAMES[:] = []
665         import_xyz.NUMBER_FRAMES = 0
666         import_xyz.ATOM_XYZ_ELEMENTS[:] = []
667         import_xyz.ATOM_XYZ_FILEPATH = ""
668         import_xyz.STRUCTURE[:] = []
669
670         # This is in order to solve this strange 'relative path' thing.
671         import_xyz.ATOM_XYZ_FILEPATH = bpy.path.abspath(self.filepath)
672
673         scn.atom_xyz_XYZ_file = import_xyz.ATOM_XYZ_FILEPATH
674
675         azimuth    = scn.atom_xyz_mesh_azimuth
676         zenith     = scn.atom_xyz_mesh_zenith
677         bradius    = scn.atom_xyz_scale_ballradius
678         bdistance  = scn.atom_xyz_scale_distances
679         radiustype = scn.atom_xyz_atomradius
680         center     = scn.use_atom_xyz_center
681         cam        = scn.use_atom_xyz_cam
682         lamp       = scn.use_atom_xyz_lamp
683         mesh       = scn.use_atom_xyz_mesh
684         datafile   = scn.atom_xyz_datafile
685
686         # Execute main routine
687         atom_number = import_xyz.DEF_atom_xyz_main(
688                 mesh, azimuth, zenith, bradius,
689                 radiustype, bdistance, 
690                 center, cam, lamp, datafile)
691
692         scn.atom_xyz_number_atoms = str(atom_number) + " atoms"
693         scn.atom_xyz_number_frames = str(import_xyz.NUMBER_FRAMES)
694         
695         return {'FINISHED'}
696         
697    
698 class CLASS_atom_xyz_error_dialog(bpy.types.Operator):
699     bl_idname = "atom_xyz.error_dialog"
700     bl_label = "Attention !"
701     
702     def draw(self, context):
703         layout = self.layout
704         row = layout.row()
705         row.label(text="                          "+ATOM_XYZ_ERROR) 
706     def execute(self, context):
707         print("Atomic Blender - Error: "+ATOM_XYZ_ERROR+"\n")
708         return {'FINISHED'}
709     def invoke(self, context, event):
710         return context.window_manager.invoke_props_dialog(self)
711         
712
713 # The entry into the menu 'file -> import'
714 def menu_func(self, context):
715     self.layout.operator(ImportXYZ.bl_idname, text="XYZ (.xyz)")
716
717
718 def register():
719     bpy.utils.register_module(__name__)
720     bpy.types.INFO_MT_file_import.append(menu_func)
721
722 def unregister():
723     bpy.utils.unregister_module(__name__)
724     bpy.types.INFO_MT_file_import.remove(menu_func)
725
726 if __name__ == "__main__":
727
728     register()