Coverage for /builds/ase/ase/ase/gui/render.py: 86.79%
106 statements
« prev ^ index » next coverage.py v7.5.3, created at 2025-08-02 00:12 +0000
« prev ^ index » next coverage.py v7.5.3, created at 2025-08-02 00:12 +0000
1# fmt: off
3from os import unlink
5import numpy as np
7import ase.gui.ui as ui
8from ase.gui.i18n import _
9from ase.io.pov import get_bondpairs, write_pov
11pack = error = Help = 42
14class Render:
15 texture_list = ['ase2', 'ase3', 'glass', 'simple', 'pale',
16 'intermediate', 'vmd', 'jmol']
17 cameras = ['orthographic', 'perspective', 'ultra_wide_angle']
19 def __init__(self, gui):
20 self.gui = gui
21 self.win = win = ui.Window(
22 _('Render current view in povray ... '), wmtype='utility')
23 win.add(ui.Label(_("Rendering %d atoms.") % len(self.gui.atoms)))
25 guiwidth, guiheight = self.get_guisize()
26 self.width_widget = ui.SpinBox(guiwidth, start=1, end=9999, step=1)
27 self.height_widget = ui.SpinBox(guiheight, start=1, end=9999, step=1)
28 win.add([ui.Label(_('Size')), self.width_widget,
29 ui.Label('⨯'), self.height_widget])
31 self.linewidth_widget = ui.SpinBox(0.07, start=0.01, end=9.99,
32 step=0.01)
33 win.add([ui.Label(_('Line width')), self.linewidth_widget,
34 ui.Label(_('Ångström'))])
36 self.constraints_widget = ui.CheckButton(_("Render constraints"))
37 self.cell_widget = ui.CheckButton(_("Render unit cell"), value=True)
38 win.add([self.cell_widget, self.constraints_widget])
40 formula = gui.atoms.get_chemical_formula(mode='hill')
41 self.basename_widget = ui.Entry(width=30, value=formula,
42 callback=self.update_outputname)
43 win.add([ui.Label(_('Output basename: ')), self.basename_widget])
44 self.povray_executable = ui.Entry(width=30, value='povray')
45 win.add([ui.Label(_('POVRAY executable')), self.povray_executable])
46 self.outputname_widget = ui.Label()
47 win.add([ui.Label(_('Output filename: ')), self.outputname_widget])
48 self.update_outputname()
50 self.texture_widget = ui.ComboBox(labels=self.texture_list,
51 values=self.texture_list)
52 win.add([ui.Label(_('Atomic texture set:')),
53 self.texture_widget])
54 # complicated texture stuff
56 self.camera_widget = ui.ComboBox(labels=self.cameras,
57 values=self.cameras)
58 self.camera_distance_widget = ui.SpinBox(50.0, -99.0, 99.0, 1.0)
59 win.add([ui.Label(_('Camera type: ')), self.camera_widget])
60 win.add([ui.Label(_('Camera distance')), self.camera_distance_widget])
62 # render current frame/all frames
63 self.frames_widget = ui.RadioButtons([_('Render current frame'),
64 _('Render all frames')])
65 win.add(self.frames_widget)
66 if len(gui.images) == 1:
67 self.frames_widget.buttons[1].widget.configure(state='disabled')
69 self.run_povray_widget = ui.CheckButton(_('Run povray'), True)
70 self.keep_files_widget = ui.CheckButton(_('Keep povray files'), False)
71 self.show_output_widget = ui.CheckButton(_('Show output window'), True)
72 self.transparent = ui.CheckButton(_("Transparent background"), True)
73 win.add(self.transparent)
74 win.add([self.run_povray_widget, self.keep_files_widget,
75 self.show_output_widget])
76 win.add(ui.Button(_('Render'), self.ok))
78 def get_guisize(self):
79 win = self.gui.window.win
80 return win.winfo_width(), win.winfo_height()
82 def ok(self, *args):
83 print("Rendering with povray:")
84 _guiwidth, guiheight = self.get_guisize()
85 width = self.width_widget.value
86 height = self.height_widget.value
87 # (Do width/height become inconsistent upon gui resize? Not critical)
88 scale = self.gui.scale * height / guiheight
89 bbox = np.empty(4)
90 size = np.array([width, height]) / scale
91 bbox[0:2] = np.dot(self.gui.center, self.gui.axes[:, :2]) - size / 2
92 bbox[2:] = bbox[:2] + size
94 plotting_var_settings = {
95 'bbox': bbox,
96 'rotation': self.gui.axes,
97 'show_unit_cell': self.cell_widget.value
98 }
100 povray_settings = {
101 'display': self.show_output_widget.value,
102 'transparent': self.transparent.value,
103 'camera_type': self.camera_widget.value,
104 'camera_dist': self.camera_distance_widget.value,
105 'canvas_width': width,
106 'celllinewidth': self.linewidth_widget.value,
107 'exportconstraints': self.constraints_widget.value,
108 }
110 multiframe = bool(self.frames_widget.value)
111 if multiframe:
112 assert len(self.gui.images) > 1
114 if multiframe:
115 frames = range(len(self.gui.images))
116 else:
117 frames = [self.gui.frame]
119 initial_frame = self.gui.frame
120 for frame in frames:
121 self.gui.set_frame(frame)
122 povray_settings['textures'] = self.get_textures()
123 povray_settings['colors'] = self.gui.get_colors(rgb=True)
124 atoms = self.gui.images.get_atoms(frame)
125 radii_scale = 1 # atom size multiplier
126 # self.gui.config['show_bonds'] is always False
127 if self.gui.window['toggle-show-bonds']:
128 print(" | Building bonds")
129 povray_settings['bondatoms'] = get_bondpairs(atoms)
130 radii_scale = 0.65 # value from draw method of View class
131 filename = self.update_outputname()
132 print(" | Writing files for image", filename, "...")
133 plotting_var_settings['radii'] = radii_scale * \
134 self.gui.get_covalent_radii()
135 renderer = write_pov(
136 filename, atoms,
137 povray_settings=povray_settings,
138 **plotting_var_settings)
139 if self.run_povray_widget.value:
140 renderer.render(
141 povray_executable=self.povray_executable.value,
142 clean_up=False)
143 if not self.keep_files_widget.value:
144 print(" | Deleting temporary file ", filename)
145 unlink(filename)
146 filename = filename[:-4] + '.ini'
147 print(" | Deleting temporary file ", filename)
148 unlink(filename)
149 self.gui.set_frame(initial_frame)
150 self.update_outputname()
152 def update_outputname(self):
153 tokens = [self.basename_widget.value]
154 movielen = len(self.gui.images)
155 if movielen > 1:
156 ndigits = len(str(movielen))
157 token = ('{:0' + str(ndigits) + 'd}').format(self.gui.frame)
158 tokens.append(token)
159 tokens.append('pov')
160 fname = '.'.join(tokens)
161 self.outputname_widget.text = fname
162 return fname
163 # if self.movie.get_active():
164 # while len(movie_index) + len(str(self.iframe)) < len(
165 # str(self.nimages)):
166 # movie_index += '0'
167 # movie_index = '.' + movie_index + str(self.iframe)
168 # name = self.basename.get_text() + movie_index + '.pov'
169 # self.outputname.set_text(name)
171 def get_textures(self):
172 return [self.texture_widget.value] * len(self.gui.atoms)
173 # natoms = len(self.gui.atoms)
174 # textures = natoms * [
175 # self.texture_list[0] #self.default_texture.get_active()]
176 # ]
177 # for mat in self.materials:
178 # sel = mat[1]
179 # t = self.finish_list[mat[2].get_active()]
180 # if mat[0]:
181 # for n, val in enumerate(sel):
182 # if val:
183 # textures[n] = t
184 # return textures